Mapstruct - Convert Object who contains and interface into himself - java

i'm using mapstruct for converting an object to another.
Into the object to convert, there's an interface, and mapstruct doesn't like that.
I was able to convert an interface to an object by implementing the default of the method and specifing the implementation to call:
public default MessagesList interfaceMapping (Integer not, List<MessageEntity> list) {
return messToImpl(numNotification, list);
}
Now the problem is that i don't know how to do a similar thing that is not a workaround, to convert an internal object signed as interface.

Just find out a good way to implement a custom code for a single object mapping:
#Mapping(target = "sender", expression = "java(new YourClass(null, messageEntity.getSenderType(), messageEntity.getSenderID(), messageEntity.getSenderContact()))")
In this way, through the expression you can define a custom code still using mapstruct definitions.
Just in case you could need to import a class not defined as source or target, just remember to annotate the class as following, to allow mapstruct to import the required class:
#Mapper(imports = YourClass.class)

Related

JSON Binding #JsonbTypeDeserializer annotation ignored on enums?

I'm converting a JAXB application to JSON-B and I've run into an issue while trying to deserialize a Java enum using a custom JsonbDeserializer inside one of my tests.
The original JSON I need to deserialize contains ints referencing the enum's constants. Therefore my custom JsonbDeserializer needs to take the int and return the enum constant with the matching ordinal. It looks like this:
#JsonbTypeDeserializer(Region.RegionDeserializer.class)
public enum Region implements BaseEnum {
REGION_A,
REGION_B;
static final class RegionDeserializer implements JsonbDeserializer<Region> {
// deserialize() method returns REGION_A for 0 and REGION_B for 1.
}
}
Then I run it like this:
try (var jsonb = JsonbBuilder.create()) {
var result = jsonb.fromJson(text, Region.class);
} catch (final Exception ex) {
fail(ex);
}
Unfortunately, here's what I get back:
java.lang.IllegalArgumentException: No enum constant Region.1
at java.base/java.lang.Enum.valueOf(Enum.java:266)
at org.eclipse.yasson.internal.serializer.EnumTypeDeserializer.deserialize(EnumTypeDeserializer.java:40)
As you can see, RegionDeserializer is not used. Instead, the default enum deserializer is used. Looking into the JSON-B docs, I see I should register the deserializer manually:
JsonbConfig config = new JsonbConfig()
.withDeserializer(RegionDeserializer.class);
Jsonb jsonb = JsonbBuilder.create(config);
...
And when I do that, the code in fact works. But here's my question - what can I do to have the JsonbTypeDeserializer annotation registered automatically? Considering I have a lot of enums I need custom deserializers for, registering them manually really doesn't scale.
EDIT 1: I have tried to use #JsonbCreator-annotated static method instead, and the result was the same. The default enum deserializer was still used.
The JSON-B specification mentions both ways of registering the custom deserializer:
There are two ways how to register JsonbSerializer/JsonbDeserializer:
Using JsonbConfig::withSerializers/JsonbConfig::withDeserializers method;
Annotating a type with JsonbSerializer/JsonbDeserializer annotation.
The fact that the annotation does not work is a bug. I could reproduce this on Yasson 1.0.6, but not on Yasson 2.0.0-M1. Perhaps updating to the latest version solves your problem?

Make Jackson Subtypes extensible without editing the Supertypes java-file

In my company we have a fixed JSON message structure:
{
"headerVal1": ""
"headerVal2": ""
"customPayload": {
"payloadType":""
}
}
I would like to have some kind of library, which allows me, to not care for the company defined message structure, and instead just send and receive the payload.
My idea was, to define the structure of the company template as one object, and use subtypes of a PayloadObject.
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.MINIMAL_CLASS,
property = "payloadType",
visible = false)
public abstract class PayloadObject {
}
Now I can create subclasses of the PayloadObject, and it can be automatically deserialized in this structure, as long as the property payloadType has a string ".SubTypeName".
This is problematic, since I cannot customize it, not even remove the superflous . in the beginning. This is unfortunately not necessarily compatible with other, existing systems in the company, we need to interface with.
The alternative is, to add a #JsonSubTypes-annotation in which I can add all the possible subtypes - which I don't want to know when writing the library. So this option won't work for me.
I thought, it might help to have the #JsonType-annoation with the subtypes, but I still have to add the #JsonSubTypes, which does not help.
Is there a way, to add subtypes to a basetype without modifying the basetypes java-file?
If this helps: We are working with Java Spring.
ObjectMapper has a method registerSubtypes(NamedType) which can be used to add subtypes for use, without having them in the annotations.
For this I created a new Annotation (I might have reused #JsonTypeName, but it might be abusive)
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface MyJsonSubtype
{
public String jsonTypeName();
}
Then I wrote me a method
public static void registerMyJsonSubtypes(ObjectMapper om, Object... reflectionArgs) {
Reflections reflections = new Reflections(reflectionArgs);
Set<Class<?>> types = reflections.getTypesAnnotatedWith(MyJsonSubtype.class);
for (Class type : types) {
String name = ((MyJsonSubtype) type.getAnnotation(MyJsonSubtype.class)).jsonTypeName();
om.registerSubtypes(new NamedType(type, name));
}
}
which uses Reflections to get all annotated types declared inside searched packages and registers them as subtypes for the ObjectMapper.
This still requires the #JsonTypeInfo-annotation on the base class to mark the object as potentially extensible, so the mapper knows, which property to use, to resolve the name, but I figure, this is is providable.
My main attention was on the problem, that I don't want to declare all future subtypes in an annotation on the base class.
I am a Java beginner though, so please share your thoughts, if this is unnecessary or could/should/must be improved.

Force mapstruct not to call has* methods

I wrote a mapstruct mapper that uses a mapping like this:
#Mapping(target = "userId", source = "id.userId")
When I looked at the autogenerated mapstruct class I stubled upon that code:
if ( !foobar.hasId() ) {
return null;
}
This is a problem for me as hasId() does not what mapstruct expects here. Can I force mapstruct somehow to not generate code that uses this method but checks for id != null or something?
I could use a mapping like #Mapping(target = "userId", expression= "java(...)") but I think there should be another way.
Yes you can force MapStruct not to use those presenceCheckers. You can find more information in source presence checking in the documentation.
Basically the only way to do this is to provide an implementation of the MapStruct AccessorNamingStrategy. You can just extend the DefaultAccessorNamingStrategy and override itsisPresenceCheckMethod.
You have access to the method ExecutableElement and you can check the type of class it is in and other things as well.
MyAccessorNamingStrategy extends DefaultAccessorNamingStrategy {
#Override
public boolean isPresenceCheckMethod(ExecutableElement element) {
//You can do your checks here. You can ignore certain methods, from certain classes
}
Remember to register your SPI with a file META-INF-/services/com.example.MyAccessorNamingStrategy
There is also the examples where you can find an example for the SPI.

MapStruct: Object.class to Custom.class mapping

I'm a newbie with MapStruct, and need some help with that.
I have a Source class, with an attribute
Object input;
Which, in runtime, returns a custom object named TicketDetails.
Now, in my target class there is a attribute named,
MyTicket myTicket;
which, I need to map with an attribute of TicketDetails object.
For, better understanding, I'm writing the normal java code example below.
SourceClassModel sourceClassModel = new SourceClassModel();
TargetClassModel targetClassModel = new TargetClassModel();
//mapping
TicketDetails ticketDetails = (TicketDetails) sourceClassModel.getInput();
targetClassModel.setMyTicket(ticketDetails.getMyTicket);
Now, my question is, how to achieve this case using MapStruct?
Either on a used mapper (see #Mapper#uses()) or in a non-abstract method on the mapper itself - in case it is an abstract class and not an interface - define the mapping from Object to TicketDetails yourself:
TicketDetails asTicketDetails(Object details) {
return (TicketDetails) details;
}
The generated method for the conversion of SourceClassModel to TargetClassModel will then invoke that manually written method for converting the myTicket property.

Creating mixins with CGLIB that implement a new interface

First off, I don't think this is necessarily a good idea, I'm just seeing if this is really possible. I could see some benefits, such as not having to explicitly convert to objects that we're sending to the client and using an interface to blacklist certain fields that are security concerns. I'm definitely not stuck on the idea, but I'd like to give it a try.
We're using Spring MVC + Jackson to generate JSON directly from objects. We have our domain object that contains necessary data to send to the client and we have a list of error strings that are added to every outgoing JSON request as needed.
So the return JSON might be something like
{ name: 'woohoo', location : 'wahoo', errors : ['foo'] }
Currently, we have a class that models what should be on the client side, but we always extend a common base class with the error methods.
So, we have:
interface NameAndLoc {
String getName();
String getLocation();
}
and
interface ResponseErrors {
List<String> getErrors();
void appendError(String);
}
We have two classes that implement these interfaces and would like to have CGLIB generate a new class the implements:
interface NameAndLocResponse extends NameAndLoc, ResponseErrors {}
Presently, with CGLIB mixins, I can generate an object with the following:
Object mish = Mixin.create(
new Class [] {NameAndLoc.class, ResponseErrors.class},
new Object [] { new NameAndLocImpl(), new ResponseErrorsImpl() } );
I could then cast the object to either NameAndLoc or ResponseErrors, however, what I would like to do is create an object that uses the same backing classes, but implements the NameAndLocResponse interface, without having to extend our common error handling class and then implement NameAndLoc.
If I attempt to cast with what I have, it errors out. I'm sure this is possible.
I think it is very similar to this, but not quite: http://www.jroller.com/melix/entry/alternative_to_delegate_pattern_with
Simply add the NameAndLocResponse interface to the Class array in the Mixin constructor as the last argument. The resulting object will implement it. You can find an example of this in this blog entry: http://mydailyjava.blogspot.no/2013/11/cglib-missing-manual.html

Categories

Resources