-
Notifications
You must be signed in to change notification settings - Fork 39
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
3rd party class customization #279
base: master
Are you sure you want to change the base?
Conversation
Signed-off-by: David Kral <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still think we shouldnt have 2 models in the API and since we cant drop annotations as of today we should stick to it instead of redoing the whole hierarchy.
Technically it does not limit any case.
I also took a few cases where the classes were in a jar I can't modify (so can't use annotations) and seems it always ends up with adapters or (de)serializers just because it is easier to understand, follow code.
So overall I'm really interested in getting this feature but I think more than ever it should be minimalistic in terms of API and more than anything not redefine the full model we already have differently.
Any hope it gets back on "real" decorators land (which are annotations in IT in most languages)?
api/src/main/java/jakarta/json/bind/decorator/BuilderProviderLoader.java
Outdated
Show resolved
Hide resolved
api/src/main/java/jakarta/json/bind/decorator/CommonDecorator.java
Outdated
Show resolved
Hide resolved
Signed-off-by: David Kral <[email protected]>
Signed-off-by: David Kral <[email protected]>
Signed-off-by: David Kral <[email protected]>
Signed-off-by: David Kral <[email protected]>
SPI is not worse than before so ok on the loading. |
IMO, *Descriptor is a better name for *Decorator classes. |
Sure, I have no problem with changing the name to Descriptor :-) |
api/src/main/java/jakarta/json/bind/decorator/CreatorDecorator.java
Outdated
Show resolved
Hide resolved
api/src/main/java/jakarta/json/bind/decorator/package-info.java
Outdated
Show resolved
Hide resolved
api/src/main/java/jakarta/json/bind/decorator/CreatorDecoratorBuilder.java
Outdated
Show resolved
Hide resolved
@@ -126,6 +127,11 @@ | |||
*/ | |||
public static final String DESERIALIZERS = "jsonb.derializers"; | |||
|
|||
/** | |||
* Property used to specify custom deserializers. | |||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we drop the two entry points from this class we can make this whole PR an appendix - same as proposing the introspector/annotation based solution - of the spec while there is not agreement on the final outcome.
Can enable to have API proposals and decide later (bean validation went that way in its time - for method validation).
Overall blocking point is to have something unified versus something duplicated for 3rd party libraries and I don't see us choosing before next release since both parties seems to either priviledge the interoperability and simplicity or the application API first (being said the introspector API enables to join the API point later if needed whereas decorator does not and keeps two concurrent models in the spec forever).
Wdyt? (trying to not block but not pollute the API too early without enabling 3rd party cases)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What exactly do you mean by "drop the two entry points from this class". I am sorry, but I don't understand what you are trying to say. Please explain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not make it explicit in the API (ie use yasson.decorators property without a constant nor a wither.
Signed-off-by: David Kral <[email protected]>
@rmannibucau If you strongly disagree with this approach I would recommend you submitting your vision as a PR so we can compare them and vote for the best approach. |
@@ -125,11 +137,11 @@ public static JsonbProvider provider() { | |||
public static JsonbProvider provider(final String providerName) { | |||
if (providerName == null) { | |||
throw new IllegalArgumentException(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likely unrelated but... javadoc says throws NullPointerException if providerName is {@code null}.
but the code does if (providerName == null) { throw new IllegalArgumentException();}
(the fix belongs to different PR...)
@m0mus I'm a bit out of time this month but long story short as discussed on slack:
So i'd start by solving 1, put an API enabling to provide an introspector manipulating the annotations instances we already have and voilà, we are 3rd party friendly and solved 2 others issues without making the API way more complex nor duplicating our own model completely :). We can revisit a more fluent API later - as CDI 1->2 did - if needed but not sure it is and hopefully javase will help us with some common GenericLiteral impl in the jre itself. |
You are right. We have an API for adding customizations at runtime, but we don't have an API to read them. We'll address it.
I don't agree here. The goal is to have two ways of adding customizations: at compile time using annotations (it's already there) and at runtime (this is what this PR is about). I don't agree that the model (I think you are talking about the customizations model) is duplicated. The model stays the same the way it's been defined in the earlier versions of the spec. We just adding a runtime API to access it. If you are talking about well-defined API vs generic API, I am not a big fan of too generic APIs. They are too wide and allow doing things going out of scope.
We need to prove implementability of API provideing at least one compatible implementation. Yasson folks are working on it. API work is in progress and we can change it as many times as we want before the release.
I am not sure I understand what you mean here. I think that this API is quite user friendly and can be used with 3-rd party objects without any problems. If you don't think so, please provide a use case. |
Signed-off-by: David Kral <[email protected]>
It is not a generic API since it is a very JSON-B specific (
To be honest Johnzon supports that since a lot of time - before JSON-B - using a kind of custom introspector injection in its model parsing and it is likely what enables the most flexibility for integrators (originally it was used a lot to bind jackson model on johnzon-mapper one). With current customization form it is a lot of work - you redefine the whole model - whereas you just want to go through the model and map what is needed visiting it in 100% of case for this use case. So here again I think we miss the right level to define the API.
As explained on slack and several other channel this API covers the end user application external customization case which is probably 5% of the use case of such an API. |
api/src/main/java/jakarta/json/bind/customization/CreatorCustomization.java
Outdated
Show resolved
Hide resolved
api/src/main/java/jakarta/json/bind/customization/CreatorCustomizationBuilder.java
Outdated
Show resolved
Hide resolved
api/src/main/java/jakarta/json/bind/customization/JsonbCustomizationBuilder.java
Outdated
Show resolved
Hide resolved
api/src/main/java/jakarta/json/bind/customization/JsonbCustomizationBuilder.java
Show resolved
Hide resolved
* @param scope required scope | ||
* @return property nillable state, otherwise empty | ||
*/ | ||
Optional<Boolean> nillable(Scope scope); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure the optional makes sense here. If empty, the spec still needs to define whether it is nillable or not when not set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional is here because the value didn't have to be set at all. Simply returned boolean is not enough in this case since we need 3 states. True, false and not set
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tt is always true or false for the runtime.
If you pass empty() you immediately do orElse(true) so at the end it is true or false.
This means you want the user to be able to explicit it or not so means the method is called or not I think, so maybe the API design is reversed compared to the goal and lead to this misleading signature?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is not true. If user didn't call nillable method, it is equivalent to the situation where annotation @JsonbNillable
has not been applied on the field/method and we have to behave correctly according to that. True/False is just not enough here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Verdent when @JsonbNillable is not on an attribute the attribute is nillable=true so true/false are strictly sufficient. Now I fully understand the intent of your API which is to let the user say "I don't care, use the (configured or not) default" but then the API is not designed for that case, it is reversed as mentionned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is true but if the user did he probably knows too since he has to use the jsonbconfig anyway with that solution so he can wire the default properly without any issue.
It is less misleading to say that it is nillable or not rather than saying it is nillable or not or maybe (still I understand you dont want an enum {TRUE, FALSE, DEFAULT} but optional means something else semantically).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What user did? :-) User can set only true or false via builder and not Optional. I don't understand what is misleading here since it just says: User either set true/false by himself or didn't set anything at all since the method has not been called. In that case value from config will be used by implementation. There is simply no misleading part here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is never misleading for the people writing it, this is why reviews are not that bad ;)
javadoc says Return if the component can be nillable in the given {@link Scope}.
, signature is not compliant to that and in any case you are nillable or not right, whatever you use global config or not so not sure the point to make it indirect for the caller is what I meant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eh... are you trying to tell me... that this whole discussion here was just about incorrect wording? OK, I will change that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hehe, no no, that even the comment is closer to the expectation.
That said I will not fight on these picky details now since I'd like the overall design to be more relevant for end users first so will stick to the main thread.
Signed-off-by: David Kral <[email protected]>
Signed-off-by: David Kral <[email protected]>
Who is integrator? Is it a person/team who works on a compatible implementation? Or it's a user integrating some 3-rd party code into his application? |
@m0mus |
You mean this PR?
I am not gonna be deprecating the runtime customization I am designing now. This is not something temporal. Visitor is not here to replace it. Just another way.
I simply don't agree with these arguments. I am still trying to make compromise and have proposed visitor with my customization objects, but to do that properly, we just have to wait. Using your "simple" annotation based solution is just unintuitive way of programming, since it simply doesn't help user in any way. That's not something regular programmer would want to do IMHO. |
This got proven a very bad way to do API. Lead to misleading and ambiguous experience to end users.
Thought that when cdi 1.0 went out but I was wrong. It is exactly as your proposal, just a doc thing but industrializable without custom wrappers for 3rd parties so just even at that level it superseeds a fluent builder API. |
What other suggestions do you have? I am really trying to make both worlds work together here, but I will simply not build my proposal on top of the literals or incorrect API. The reason for introducing visitor later is just because I want to make it right in terms of the API. I think it is time for you to fully introduce your desired solution in details, so we can review it.
CDI uses that approach and it is completely fine in terms of what they are doing, but it is something, what I do not believe, belong to the JSONB code and usage style. |
@Verdent i sent one proposal - based on johnzon - on our slack chan, but we can also reuse introspector kind of api for the high level idea, both work but miss the jsonb context - this is where visitor came from (think adapter, deserializer, which must be provided to the customizer before it contributes some customization for ex). So overall api can be something like:
Base context would be an inner interface:
Type and property flavors will just expose, resp., the underlying getType()+skipProperty(String)+register(Annotation...)+registerProperty(Annotation...) and Optional+Optional as getters. Nothing more needed, handles all types customizations including lists/maps, keep focused on our current model and finally is build time friendly since no reflection is required at runtime (even if build will stay simpler and way faster using it ;)). |
Well... it's not that simple as you are still claiming it to be. Alright lets do some tests here.
Show me how the usage of this API would look like, when I want to have a different name for serialization and for deserialization and for example |
About the serial/deserial names, JSON-B does not support it until you use a custom deserializer/serializer (I hear you can put a setter and getter not asymmetric but not 100% sure it happens often enough) so at the end you |
public class Pojo {
private String valueOne;
private String valueTwo;
//getters and setters are also present
} So you are really trying to tell me, this is simpler, faster to work with and easier to use then my proposal? It gets messy and overly complicated with just a few properties. In fact 2 are enough to have unnecessary complexity of ifs or switch statements. public class MyJsonbModelCustomizer implements JsonbModelCustomizer {
@Override
public void onType(TypeContext context) {
context.register(new JsonbNillable.Literal();
}
@Override
public void onSerializationProperty(PropertyContext context) {
context.registerProperty(new JsonbProperty.Literal("serialName"));
}
@Override
public void onDeserializationProperty(PropertyContext context) {
context.registerProperty(new JsonbProperty.Literal("deserialName"));
}
} |
From my experience it is clearly easier to integrate with 3rd party libraries and classes than an explicit highly verbose API + you still didn't solve the model duplication. |
Yes, if you are registering property, it would require more then just one annotation.
I am not claiming you cannot do it without my solution. I am claiming my solution is easier to use.
This is simply not true. Now try to demonstrate how it would look like for 3 or more different properties where you want to have different customization (for example names) for serialization and deserialization. And also try to make some mechanism which would execute your proposed solution only for a specific class and not for all. Because now it is basically widely used for each type.
I don't believe there is any duplication, that means I do not see anything to fix. And once again I am not against visitor in general, I can see its reasoning. I am against the literals in our APIs and having visitor only without the easy way to do stuff. Visitor would be there as more of a hardcore part if user really needs that. |
If it is a virtual one it requires just the both functions (to be bidir), if we stick to customizations just annotations as in the example (but can be JsonbNumberFormat.Literal and others too indeed)
In one very particular case yes, in all others I don't think so. Plus, it duplicates the model which is a big issue for me.
Well it is as you can see:
On your last point: I don't want to make a lot of convenient helper functions, this always lead to a noisy API which is more bothering and does not encourage people to learn proper ways to solve their issues. |
That it duplicates something is just your opinion. From my point of view it is perfectly fine to have it like this. It is easier to use in most of the needed cases. And for those, it is not, visitor will be presented to be able to use. As I mentioned before.... a bigger hammer to do the stuff.
Eh... I am not sure what to say here. I have several issues here. This still does not address multiple properties or specific class. Another is that JsonbProperty annotation doesn't have to be there and most likely will not be and that means it cannot be done simply like that. I know you are trying to put everything on a single line just to look it is simpler and less chatty. But I would prefer to do it correctly and with all cases covered.
That's exactly what my proposal is about. Visitor is for more extra needs. I would be more then happy to come up with some sort of compromise. I have already introduced several of those, but literals are simply no go for me. I will go over that line. |
You didnt get it. Your solution solves end user customization, period.
It is as explained in the comment. Give a try if you doubt. |
others -> you
I did. So you think that this method should basically just fail with NullPointerException since otherwise I am not sure how the impl will even know to fall back. |
It definitely makes sense to use reflectionless Object Model API because we are targeting to Jakarta Core profile which is going to be build time processing friendly. |
Folks, this conversation becomes never ending. Both parties have strong opinion and no one wants to step back. It's getting close to October deadline and we may not have enough time to deal with the implementation and TCKs. I see two options:
I would like all project committers to vote. I'll close the ballot in a week at Sep 23rd 13:00 CEST. @njr-11 @Verdent @edbratt @jansupol @jimma @lukasj @otaviojava @pdudits @rmannibucau @tomas-langer @ivanjunckes please vote in the comments. I hope I didn't forget anyone. |
* @param scope required scope | ||
* @return property transient state, otherwise empty | ||
*/ | ||
Optional<Boolean> transientProperty(Scope scope); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional of boolean seems weird, if we want a third
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was designed exactly to have the third option here :-) It should correspond to whether it has been set to true/false explicitly or wasn't set at all, in which case @JsonbTransient of the property should be reflected (if present) I was trying to avoid using true/false/null
* @param scope required scope | ||
* @return property nillable state, if not explicitly set empty is returned | ||
*/ | ||
Optional<Boolean> nillable(Scope scope); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same issue here about optional of boolean
@m0mus I like MVPs, so I vote to merge as it is and then move to the next step. |
@m0mus without surprises, I think this misses the bbig opportunity to have an unified model and unified API solving > 3 issues (missing features) so I'd keep it as an extension not belonging to the spec requirements (= agree it can be a DSL end users like on top of the actual spec API but nothing more) so I'd be to not merge it. |
Signed-off-by: David Kral <[email protected]>
I'm for merging this. |
I am a bit puzzled here. I am for merging it, but I want to do it right. There is possible problem I can see and that is the moment, when we decide to add that visitor and introspector functionality, I have mentioned before. I would like to have these two features build on top of this customization PR and the problem might be, that we will need to change something in this customization design, but if it is already released and it is breaking change, we will not be able to. So I might vote for postponing and merge when visitor and introspector do have all the required parts ready and are fully designed. Does this thought make sense? or you think it will be fine to merge it now, since I do have the design of the visitor and introspector more or less ready and we might not need later to change the customization at all? |
The open question for Jakarta EE 11 is the possible replacement of Java reflection API with a metamodel for compile-time (annotation) processing. Such a thing would be required by multiple specs that would want to focus on speed (thank you Quarkus), starting with CDI lite, up to JSON-B. Introducing an API that handles the annotations directly can cause issues for EE 11 and the new API could have been immediately deprecated in EE 11. We do not know for certain what requirements this compile-time processing brings, and hence I agree with David to postpone this very API change until we have a more complete idea of the requirements. Then we will be able to design the API for introspection, too. |
I guess we can fully ignore reflectionless because:
So long story short, the big risk there is to create an api not reaching enough consumer coverage and superseeded in a next version we already envision even if we dont have the api yet. Side note: we dont have to await an ee version to release a major jsonb version, we can be faster if we reach a compromise. EE just gets the current last version in last release plan "sprints". |
@rmannibucau This issue is likely not to right place to discuss reflectionless. But it is a big topic right now for EE 11. I completely agree that it can be ignored, and the benefit not being used. I agree that JDK provides everything needed so we do not need anything new from CDI or whomever. We may not benefit from what is provided by other projects and we can reinvent the wheel. But I am not sure it is the right way to go. We may see where the EE world is heading soon; I expect a wide discussion once EE10 is dealt with. Anyway, I understand that you agree with postponing the PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the feature and can see the where it could be useful.
The javadoc should however consistently describe the semantics of the methods, and we shouldn't introduce any types that have no purpose for the user of the API.
import jakarta.json.bind.spi.JsonbProvider; | ||
|
||
/** | ||
* Type customization. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is the entry point to the feature, I miss more explanation about the effect of using a type customization in the Javadoc:
- Does it fully override information provided via annotations?
- How does it cooperate or interfere with adapters and serializers defined for the type?
An example would be nice as well
/** | ||
* Return {@link PropertyOrderStrategy} of the decorated type. | ||
* | ||
* @return property order strategy instance, otherwise empty |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation for most of the getters in the package is confusing.
The pattern "Return X of the decorated type" raises obvious question -- what is "decorated type"? If it stands for what getType()
then either javadoc for getType()
should explicitly mention decorated type, or documentation should use "type which is customization bound to" instead of "decorated type".
"Return X, otherwise empty" is also unclear -- What does empty return mean? That decorated type has no defined property order strategy? Or that it has no customized property strategy, and therefore default (i. e. annotation-based if it exists on underlying type) behavior will be active? I assume latter therefore the wording should rather follow pattern "Return customized X if defined, otherwise empty"
/** | ||
* Common interface for all the customizations. | ||
*/ | ||
public interface JsonbCustomization { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my opinion the type hierarchy of the customizations does not serve any purpose for the user and makes API harder to navigate. I'd drop this entire hierarchy and limit public API just to the interfaces that should be used directly by the user.
I can see how this can be convenient for implementor, but implementor is free to build its implementation class hierarchy instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm yes I kind of agree, but the whole hierarchy has been made this way to prevent having method duplication :-) Or do you agree with having it and just hide it as package private and expose just the end interfaces?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You got me reading Java Language Specification with this question, and it doesn't directly list the consequences. I believe it's better to inline the interfaces.
/** | ||
* Decorated parameter customization. | ||
*/ | ||
public interface ParamCustomization extends JsonbCustomization, ScopelessCustomization { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ParamCustomization
as it seems is not really a customization, it is a parameter of CreatorCustomization
.
Should it follow the same naming pattern, and should it be top level interface?
I'd propose name CreatorParameter
instead, moving it into CreatorCustomization would be also an option to explore.
/** | ||
* Scope of upon which the customization should be used. | ||
*/ | ||
public enum Scope { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recommend using more specific name, so this doesn't creep into autocomplete for e. g. jakarta.inject.Scope
.
CustomizationScope
would be more fitting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this seems reasonable to me. Original thought was to avoid having long enum name
T deserializer(JsonbDeserializer<?> deserializer); | ||
|
||
/** | ||
* Ignore deserializer of this component. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ignoreNillable
above says "Ignore nillable customization", while this says "Ignore deserializer".
What is the semantic of these ignore methods? Resetting the customization, or overriding default beaviour, e. g. ignoring deserializer when one is defined with an annotation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whole concept of the ignore methods should be in place to ignore specific annotation on the component, other customizations (and also inherited ones) which apply to the component should be applied. I am still playing a bit with an idea of having just a single ignore(Class<? extends Annotation>)
method. I am still not sure if that is not more clear. What do you think about this common ignore method? Would it be better? Or would you prefer to have separate methods for each customization to ignore.
Anyway yes, javadoc of this version is not very clear. I do have it fixed locally, but not yet pushed :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason I asked was because one can also do somePropertyCustomization.toBuilder().ignoreDeserializer()
. What is the effect of this call if somePropertyCustomization
defined a serializer?
The customization of every attribute is from domain Default|None|Custom(value)
, where Default represents no customization, so whatever spec+class annotation prescribe, None represents spec while ignoring class annotation, and finally Custom is customized value from customizer. Usually one starts at Default and with ignore
method can set processing to None
, with set(x)
method can set processing to Custom(x)
. But with toBuilder
you can start in any of the states and you need transition path to any other state. The common ignore method will only solve part of the problem, while introducing the binding to annotations and it is clear where it would go from there ;)
Clean model of this would be to have every customization attribute represented as type similar to Optional<T>
, where it is either Customization.ignored()
, Customization.annotated()
or Customization<T>.of(T value)
. It is possible to have single getter/setter pair for every attribute and cover all of the possible states.
Additionally a convenience setter can be added, where non-null value represents of(value)
and null represents annotated()
.
Another approach is to have provider to return Builders with full mapping, but that turns it into introspection API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This also shows weakness of toBuilder()
methods. It cannot be really reused for different property names, in case I have common customization to apply to more fields. Either names should also be modifiable in builders or method toBuilder(name)
should also exist.
One final alternative is to drop toBuilder()
methods, and rely on TypeCustomizationBuilder.property(String,Consumer)
for sharing settings. Then everything starts in annotated
state.
@pdudits Thank you for your feedback. I definitely agree that javadoc should be improved and I will do that :-) It contains a lot of inconsistencies and unclear formulations, which I am working on getting rid of. |
Signed-off-by: David Kral [email protected]