-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make our Converter Interface Converter<S,T> #5
Comments
@dmlloyd What do you think of this? |
Are you expecting that converters get automatically chained? If I've registered a |
I'm not so sure if we should go that route yet. I fear that if we go that route, we may become another full object mapper library like MapStruct, ModelMapper, Dozer, etc. We may reach the conclusion that we will need chaining, but I think not at this stage. I think that it is acceptable that if you require conversion of composed objects, it should be handled manually calling the appropriate converts in the entry point converter. What do you think? |
I'm not sure I have an opinion yet, just questions. :-) Another case that I wonder about is collection conversion. How would it work? Today since converters are one-dimensional, we can easily define every possible conversion in terms of other converters (for example we can compose optional, list, and a scalar type all into one chain) in a very straightforward way. But what would be the correct composition approach here? Would we have a converter from a One feature that SmallRye Config misses that I think would be powerful would be automatic composition. For example I should be able to register a global converter like this: public final class MySetConverter<T> implements Converter<Set<T>> {
private final Converter<T> delegate;
public MySetConverter(Converter<T> delegate) {
this.delegate = delegate;
}
public Set<T> convert(String input) {
// do the conversion here using my custom Set impl
}
} Then the config framework examines the signature, notes I have a type var Is such a feature even possible when converters are two-dimensional? I'm not so sure. |
Most likely Collections conversion will need to be handle differently. We need to only require the element type converter of the Collection to be implemented, and then we handle the rest. This means that for these cases we only support Then you can have specialised Converter types, for instance I see no reason for smallrye/smallrye-config#40 wouldn't work for two-dimensional types. In theory, you should able to implement that. On practice, it may provide too much work :) |
I don't mean two dimensional arrays, I mean two dimensions of typing. The canonical theoretical problem is like this: if I have a |
Ops. Sorry. I meant types not arrays. Fixed. That is an interesting question. I would probably lean to a |
Sure, but that's a subjective argument, and thus the exact opposite argument could be made with equal validity. The fact is that both converters have equal validity from any objective measure, therefore whatever option is chosen will be wrong to some extent. And who wants to use wrong software? But we don't need to give up all hope; every problem is solvable. But before we go into that, do we have other use cases beyond Config and JWT that need to be evaluated? |
Sure. But we are here to fix the issues we took the wrong decision. I don't loose hope with you here :) Right now, I've looked into this with the JWT perspective, because it was an obvious use for the library and even have open issues about supporting Converts like Config. Maybe OpenTracing / OpenTelemetry could also benefit from these, so you could inject and convert to types directly from the trace context (but we will be dealing with String here). |
OK so we have two cases; in one case, the input is a String and in the other the input is some structured type of known complexity. I would go a little farther and say that considering smallrye/smallrye-config#216 and other YAML-related issues, plus eclipse/microprofile-config#550, we might consider that configuration sources also would want to use structured types of known complexity rather than dealing just in raw strings all the time. So for the sake of exploring this idea, let's assume that is the case, and let's assume we have some intermediate representation or representations that encapsulate all of the possible structured types. Now things are interesting because we can have an From the perspective of config, configuration sources could produce the intermediate type(s) instead of The final feature of such a design is that the converter ambiguity problem is solved definitively. Every combination of input and output can be supported equally well because every converter type is one-dimensional. But, what would the intermediate type(s) look like, and why? That's the next challenging question. |
It's also worth nothing that |
And do you have any ideas of the intermediate types? Quite frankly, I couldn't think on any acceptable intermediate type. Unless I didn't understand the concept fully, in practice you will have a 2 step conversion. One from source to the intermediary type and another one from the intermediary to destiny. Is that correct? |
Right, if you do both halves of the concept - unless your intermediate type already includes your conversion source (or target). For example if the intermediate type (or one of the intermediate types) is a string, then you don't need an input converter to convert from string. |
Ok, let go for a more complex case with the So I have an Do we have specialised |
On the one hand, it could be possible to have a structured intermediate type that can (like JSON or YAML for example) be an integer, FP number, string, boolean, or a list or map of any intermediate type. This solves the problem elegantly, in a way: the input could be JSON, or YAML, or a plain string; the value becomes the intermediate structured type; the output converter interprets the open ended type and produces an However, some context is lost. Perhaps interpretation of an So, this surrounding context would have to be carried forward somehow. The input converter would have to know where the information comes from in some standard way that can be interpreted by the output converter in a general way. This mechanism would have to be built to prevent the output converter from generating an object wrongly due to an unrecognized input context. |
I'm not sure if this answers my questions completely. My concern is that by introducing this intermediate type, we would be performing unneeded operations on structures that are already optimised for specific outputs. Should we have a single Maybe we can think about this as |
Maybe. But that might be an unavoidable cost of a two-dimensional conversion framework that also has a sane definition of "correctness".
An easier way to look at it might be to view it as a "logical" input type. This manifests in two ways: first of all, an object might have more than one valid JSON representation for various reasons (differing specs for example); second of all, a JSON representation might itself be possible with more than one different Java type (for example JSON-P versus org.json vs...). So already the problem is complex. Logically we may know how to generically represent an
This works with config because configuration "layering" is an understandable and useful concept. I'm not sure that layering converters is useful. |
Loving this discussion, but should we try to reach a conclusion? :) (I'm pretty sure we will discuss plenty over this in the future) We still have the open question about the intermediary type. Do you have any ideas? |
A design discussion can come out in one of two ways: prematurely (and wrong), or correctly (however long it takes). 🙂
Well I haven't quite proposed anything yet for a reason TBH. Personally I'm not convinced that our use cases can coexist in a rational way, but am willing to continue brainstorming to see if something comes out of that. Being "selfish" (from the perspective of config), the ideal intermediate would be like I said: numerics, string, boolean, and lists and maps. I wouldn't propose a literal object abstraction of these types, as that would amount to lots of redundant objects, but the config source would be able to get values in each of these types (putting the responsibility of conversion of just these types on the side of the config source), while the converter would accept any of these values types and handle it in the proper way (even if the proper way is to throw an exception). But there are numerous technical problems that definitely arise from this approach, so I wouldn't actually go in this direction until/unless those could be worked out. And, of course, this completely ignores any other use case, so is unlikely to be adequate in these cases. |
These pretty much cover Config implicit converters. We can assume that other complex cases will always have to be represented as String (like we have today). From the Config perspective, this is fine. Now, is there a way that we can optimize this, when we don't control the origin? Carrying over a context, might be too heavy, plus you already have the perfect context with the structure itself. I guess that if just assume String for everything, this become way more simple. Maybe the |
Right now, our Converter interface is generic type for the conversion result, but the conversion original value is fixed to a String.
It might be interesting for our top level conversion to support a generic type on the original value as well, like:
The motivations behind this is to better support requirements in MP JWT. Original issue here:
eclipse/microprofile-jwt-auth#100
The source object from where values are retrieved from is a Json structure (the JWT). Values are represented as the Json counterparts (JsonObject, JsonNumber, etc), so in fact, our conversion needs to call
.toString
on these and perform additional operations back and forward for the final conversion to take place.With String conversion
With Source and Target
The text was updated successfully, but these errors were encountered: