I have a rather big bean (~ 100 properties) that is mapped into several smaller objects. It may occur that the smaller target objects have properties with the same name as in my source bean, but not with the same semantic meaning.
I would like MapStruct to behave in this specific case to map only what I explicitly tell using a #Mapping annotation and not perform the usual automatic mapping.
The MapStruct documentation tells me just this:
In the generated method implementations all readable properties from the
source type (...) will be copied into the corresponding property
in the target type (...).
I didn't find any configuration option switching this behavior off.
Can it be done?
Switching off implicit field mapping is possible via #BeanMapping(ignoreByDefault = true) mapping method annotation since MapStruct 1.3. From MapStruct 1.3.1 Reference Guide:
By means of the #BeanMapping(ignoreByDefault = true) the default
behavior will be explicit mapping, meaning that all mappings have to
be specified by means of the #Mapping and no warnings will be issued
on missing target properties.
As stated in Mohamed's comment, you could ignore these properties explicitly.
There is no switch as you describe it. Personally I'd probably write that specific mapping from hand instead of explicitly configuring all the mappings through annotations. Granted, you'd still benefit from type conversion etc., so it may still be beneficial, it really depends on your use case.
I had a similar problem like you say, I solved it using decorators
#Mapper
#DecoratedWith(PersonMapperDecorator.class)
public interface PersonMapper {...}
see the documentation (MapStruct 1.2.0.Final Reference Guide), chapter: 12. Customizing mappings
I hope that it is also useful for you
Related
I use a library that provides an annotation #LibraryAnnotation with a Boolean parameter parameter. The default is set to true by the authors of the library.
Unfortunately, in almost all my use cases, I prefer the annotation with parameter = false. To achieve the desired behavior, I use #LibraryAnnotation(parameter=false) instead of #LibraryAnnotation every time. This is error prone since one easily forgets to set the parameter.
I am wondering if there is a way to simplify things by changing the default value for the parameter of #LibraryAnnotation or by defining a custom annotation that behaves like #LibraryAnnotation(parameter=false), but does not require setting a parameter.
(In this particular case, the library is lombok, but the question could be relevant for parametrized annotations provided by any library. Update: Lombok offers default parameter configuration via a lombok.config file, but I am still interested in a general solution.)
You can define your own annotation and use that instead. Something like:
#LibraryAnnotation(parameter = false)
public #interface MyLibraryAnnotationFalse {
}
I'm reading java language specifications (JLS): annotations
An annotation denotes a specific invocation of an annotation type
(§9.6)
And in 9.6:
An annotation type declaration specifies a new annotation type, a
special kind of interface type.
So e.g. #annotation1 should invoke annotation type annotation1. I could not find info what it means by web search or questions here. All I've found only about invocations of methods of interfaces, not interface types. I've read what some build-in annotations do of cause, e.g. infamous #Override, however I want clear knowledge preferably with links to JLS what interface type invocation is as I've read annotations are used by many useful frameworks which I want to use efficiently.
If you write #SomeAnnotation you basically create in instance of that annotation type (there might be some caching but I'm not aware of this). This becomes especially apparent when an annotation has data, e.g. #SomeAnnotation(name="Alexei"). In that case you could get the annotation instance of type SomeAnnotation and then invoke name() on it to get the value "Alexei").
I've read annotations are used by many useful frameworks which I want to use efficiently.
Most frameworks use reflection to inspect your classes and collect information on the annotations, e.g. via Class.getAnnotation(SomeAnnotation.class) and many other similar methods. That information is then used to do whatever the framework needs them for, e.g. CDI would use the scope annotations to build its internal bean repository.
To use those frameworks you don't have to know about the specifics of how they use the annotations or what invocation actually means. Just use the annotations themselves as the framework requires you to do.
If you want to develop your own framework then you might need some more information, especially on the reflection capabilities.
As far as my understanding of the link jls you posted, annotations types are special interface types and one should not think that invocation in that context means same invocation as say for a method. Compiler inserts markers with code and they can be used later (or right during compilation as with #override) .
I have a RESTapi written using Jersey Framework. Along with it there is a POJO class. Now, my need is how do I make a particular field optional in my POJO so that the api will work regardless of that optional field? I want the API should work in both the cases, i.e
if I give that optional parameter then also,
if I don't give then also it should work.
Java 8's Optional was mainly intended for return values from methods, and not for data properties of Java classes(POJO), as described in Optional in Java SE 8:
Of course, people will do what they want. But we did have a clear
intention when adding this feature, and it was not to be a general
purpose Maybe or Some type, as much as many people would have liked us
to do so. Our intention was to provide a limited mechanism for library
method return types where there needed to be a clear way to represent
"no result", and using null for such was overwhelmingly likely to
cause errors.
The key here is the focus on use as a return type. The class is
definitively not intended for use as a property of a Java Bean.
Witness to this is that Optional does not implement Serializable,
which is generally necessary for widespread use as a property of an
object.
[credits] : https://blog.joda.org/2014/11/optional-in-java-se-8.html
I'm guessing you are referring to the serialisation of fields in your POJO. Since you have not stated which version of jackson you are using, you'll have to use one of these annotations to allow nulls:
Can be used on either class or getter:
#JsonInclude(Include.NON_NULL)
If you are using Jackson <2.x, use this:
#JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
The NamingStrategy was already being marked as deprecated in Hibernate 4.2/4.3 (HHH-7079). Starting with Hibernate 5, now it will shipped with two replacements(?) interfaces ImplictNamingStrategy and PhysicalNamingStrategy (HHH-7078) and have finally ditched support for the old NamingStrategy. That's why Spring's upcoming Hibernate5 supported has even removed the configurer namingStrategy() and favor of implicitNamingStrategy() and physicalNamingStrategy(). So far, so good.
Although it is mentioned in some documents (i.e. in the incomplete working-5.0-migration-guide.md) and in (generated) release notes for the upcoming Hibernate 5 (as of today), I've found no concrete example how to use these actually.
Perhaps I've missed something, but neither the JavaDoc nor the issues shows any evidence of the idea both strategy types. Furthermore I've already one strategy based on NamingStrategy: a custom OracleNamingStrategy which is based on the well-known one.
While I'm interested in a proper solution in code (obviously), the actual issue is getting a working migration document and/or the conceptual idea of the restructured naming strategy.
Also related:
ImprovedNamingStrategy no longer working in Hibernate 5
Put below key value pair in your hibernate configuration file
hibernate.implicit_naming_strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl
hibernate.physical_naming_strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
If you are providing #Table and #Column annotation in your entity classes with names provided with an underscore i.e. user_id i.e. #Column(name="user_id"), it will take the column name as user_id; if you give it as userid then it will change to user_id if you use no strategy or implicit strategy (specifically spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl). So, if you want a strategy where the entity attribute name changes to one with underscore and lowercase letters i.e. something from userId to user_id, you should use implicit or no strategy (which actually uses implicit strategy).
If you don't want your naming strategy to add an underscore to the column name or class name, then the strategy that you need to use would look like:
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl. The things that you provide in annotations #Table and #Column’s name attribute would remain as it is.
If you don't want to provide annotations and want to manually handle the table name and column names, you should extend the class org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl and override the required methods. If you still use annotations for some of the cases here, remember the overridden methods will apply on the names written in those annotations.
spring.jpa.hibernate.naming.physical-strategy=example.CustomStrategy
To quote this link :
Some developers think that the Java compiler understands the tag and
work accordingly. This is not right. The tags actually have no meaning
to the Java compiler or runtime itself. There are tools that can
interpret these tags
.
If the information contained in the annotation is only metadata, why wont my code compile if I annotate wrongly ? That particular annotation should be simply ignored right ?
Edit :
Just to provide an example... A simple JAX-RS web service on Jersey uses an annotation like :
#Path("mypath")
Now, if I change this to :
#Paths("mypath")
OR
#Path(123)
it should NOT stop me from compiling the code according to the above link...
The article is wrong for at least some annotations. Thinks like #SuppressWarnings and #Override the compiler does have very specific knowledge. In fact, the article points this out itself:
Metadata is used by the compiler to perform some basic compile-time checking. For example there is a override annotation that lets you specify that a method overrides another method from a superclass.
Quite how it can be used by the compiler if "the tags actually have no meaning to the Java compiler", I don't know...
Additionally, even for annotations that the compiler doesn't attach any semantic meaning to, it will still verify that when you try to specify particular arguments etc, that those arguments have sensible names and types for the annotation you're using.
Annotations are basically a special form of interface, so the compiler has to be able to load the annotation definition in order to encode the information so it can be included in the class file. Once it's in the class file, the class loader will load it as part of the class, so that annotation-processing tools can access the information. The compiler will verify that only defined arguments are used, as well as supplying default values for attributes that aren't specified (and have defaults defined).