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.
Related
Mapstruct always generate mappers that use a default empty constructor and setters to construct an object.
I need mapstruct to construct objects using parameterized constructor instead.
I have this mapper configured using maptruct:
#Mapper(componentModel = "spring")
public interface FlightMapper {
FlightBooking flightBookingPostRequestDtoToFlightBooking(FlightBookingPostRequestDto flightBookingDto);
}
The implementation that mapstruct generates uses the default constructor without parameters:
public FlightBooking flightBookingPostRequestDtoToFlightBooking(FlightBookingPostRequestDto flightBookingDto) {
if ( flightBookingDto == null ) {
return null;
}
FlightBooking flightBooking = new FlightBooking();
flightBooking.setFlight_booking_id( flightBookingDto.getBooking_id() );
return flightBooking;
}
But I need this implementation with a parameterized constructor instead:
public FlightBooking flightBookingPostRequestDtoToFlightBooking(FlightBookingPostRequestDto flightBookingDto) {
if ( flightBookingDto == null ) {
return null;
}
FlightBooking flightBooking = new FlightBooking(flightBookingDto.getBooking_id());
return flightBooking;
}
How can I configure mapstruct to achieve this? I haven't found any responses in the official documentation. Thanks in advance
Since the 1.4 release, MapStruct supports using constructors when instantiating mapping targets.
One solution would be marking the parametrized constructor as #Default. For more possible solutions and more details on how the Constructor support works have a look at the reference guide.
ObjectFactory is the way to go.
By default beans are created during the mapping process with the
default constructor. If a factory method with a return type that is
assignable to the required object type is present, then the factory
method is used instead.
Factory methods can be defined without parameters, with an #TargetType
parameter, a #Context parameter, or with the mapping source parameter.
If any of those parameters are defined, then the mapping method that
is supposed to use the factory method needs to be declared with an
assignable result type, assignable context parameter, and/or
assignable source types.
I left to you the pleasure of reading documentation and solve the problem :)
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)
I have already posted something similar but I still trying to zero in on my problem.
Thanks for bearing with me.
It would appear that jackson is not calling a mixin as it should and I can't tell why.
"Element" is an interface not a class. It is normally instantiated with a static factory call as shown in the mixin (below). The way I understand it, when jackson sees the interface: Element.class it should look up the mixin then execute the method that has the #JsonCreator annotation. None of this is happening. If it were, I would see output from the logger. Instead, as one can see in the error message (way below), jackson is trying to treat my interface as a class and can't.
Why isn't my mixin working?
Here's the mixin:
public class ElementMixin {
private static Logger log = LoggerFactory.getLogger(ElementMixin.class);
#JsonCreator
public static Element create() {
log.error("Element==>");
return FhirFactory.eINSTANCE.createElement();
}
}
Here's how I register it with the mapper:
ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(Element.class, ElementMixin.class);
Here's how I am running things:
// Instantiate my interface, put some data in and serialize.
Element ela = FhirFactory.eINSTANCE.createElement();
ela.setId("CBAEL");
StringWriter writer = new StringWriter();
mapper.writeValue(writer, ela);
// Now try to deserialize into a new instance.
StringReader reader = new StringReader(writer.toString());
Element elp = mapper.readValue(reader, Element.class);//Error thrown
assertNotNull(elp);
The error:
com.fasterxml.jackson.databind.JsonMappingException: Can not construct
instance of fhir.Element, problem: abstract types either need to be
mapped to concrete types, have custom deserializer, or be instantiated
with additional type information at [Source:
java.io.StringReader#4fe533ff; line: 1, column: 1] at
com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:255)
at
com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:1007)
at
com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:150)
at
com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3807)
at
com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2844)
at
gov.nist.forecast.fhir.resources.IndexResourceTest.testParametersJSON(IndexResourceTest.java:173)
Mix-ins only associate annotations; they can not and do not add any fields or methods -- no bytecode generation or manipulation is added. So while you can add annotations to indicate methods that already exist in target (including static factory methods) should be used, nothing (aside from annotations) defined in mix-in will ever get called or used.
I am working on a particular task which consisters of different phases. In the first phase I created a class(a) that reads a property file and saves the data into a hashmap. This class has a method (1) that will get the key and return the corresponding value from the map, if there is no entry in the map the key enter will be returned.
In the second phase I created a custom converter class (b)the extends the DozerConverter class I then autowired class (a) and in the method convertTo() that is provided by the DozerConverter class I simpley call the method (1) of class (a).
Since I am using Spring I have used the following code
#Bean
public DozerBeanMapperFactoryBean configDozer() throws IOException {
DozerBeanMapperFactoryBean mapper = new DozerBeanMapperFactoryBean();
mapper.setCustomConverters(Collections.<CustomConverter> singletonList(new ErrorCodeConverter()));
return mapper;
}
The part that I am confused about is how can I get the ErrorCodeConverter from the mapper object and use this class which is my custom converter. I have found lots of examples where they provide xml mappings but I don't want any xml mapping. This job is being done for me by class (a). I have wrapped class (a) with custom converter to make using of dozzer mapper api.
Any help will be highly appreciated.
I just take a look in Dozer code from my local (5.3.1), it appears Dozer is designed to apply Custom Converter at 'field' level not 'class' level through API.
You can tweak a bit which wrap your object as a field of another class so you can use API to perform CustomConverter. Hope it helps.
Nghia
Is there any way to read and print the object attribute dynamically(Java) ? for example if I have following object
public class A{
int age ;
String name;
float income;
}
public class B{
int age;
String name;
}
public class mainA{
A obj1 = new A();
method(A);
method(B);
}
the output should be like
While running method(A):
Attribute of Object are age,name,income;
While executing method(B):
Attribute of Objects are age,name;
My question is I can pass various object in method(), is there any way I can access the attribute of the differnt object in general.
You want to use The Reflection API. Specifically, take a look at discovering class members.
You could do something like the following:
public void showFields(Object o) {
Class<?> clazz = o.getClass();
for(Field field : clazz.getDeclaredFields()) {
//you can also use .toGenericString() instead of .getName(). This will
//give you the type information as well.
System.out.println(field.getName());
}
}
I just wanted to add a cautionary note that you normally don't need to do anything like this and for most things you probably shouldn't. Reflection can make the code hard to maintain and read. Of course there are specific cases when you would want to use Reflection, but those relatively rare.
Using org.apache.commons.beanutils.PropertyUtils we can do this. If the proper getters and setters are defined for the bean we can also dynamically set the value:
import org.apache.commons.beanutils.PropertyUtils;
import java.beans.PropertyDescriptor;
public class PropertyDescriptorTest {
public static void main(String[] args) {
// Declaring and setting values on the object
AnyObject anObject = new AnyObject();
anObject.setIntProperty(1);
anObject.setLongProperty(234L);
anObject.setStrProperty("string value");
// Getting the PropertyDescriptors for the object
PropertyDescriptor[] objDescriptors = PropertyUtils.getPropertyDescriptors(anObject);
// Iterating through each of the PropertyDescriptors
for (PropertyDescriptor objDescriptor : objDescriptors) {
try {
String propertyName = objDescriptor.getName();
Object propType = PropertyUtils.getPropertyType(anObject, propertyName);
Object propValue = PropertyUtils.getProperty(anObject, propertyName);
// Printing the details
System.out.println("Property="+propertyName+", Type="+propType+", Value="+propValue);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
To set the value of a particular property:
// Here we have to make sure the value is
// of the same type as propertyName
PropertyUtils.setProperty(anObject, propertyName, value);
Output will be:
Property=class, Type=class java.lang.Class, Value=class genericTester.AnyObject
Property=intProperty, Type=int, Value=1
Property=longProperty, Type=class java.lang.Long, Value=234
Property=strProperty, Type=class java.lang.String, Value=string value
You can use reflection to get every field from your object (if security configuration allows you).
If you need it not for the sake of self-education, then it may be worth using ReflectionUtils from Apache Commons.
You can use reflection, but the API is not very nice to use. But what you are trying to do is not at all object-oriented. The A and B should have method "print yourself" which would output their values (you should specify the method in superclass/interface to call the method using polymorphism).
I think I would consider a different approach.
If you really want to treat these like data is there any reason they couldn't be hashtables (Do they have associated code)?
Reflection will do it but it's a last resort--you should always seriously consider different approaches before dropping to reflection.
Cases where you must access variables like that exist--like database mapping (Hibernate) and injection (Spring). You might want to consider if a packaged solution like that fits your need so that future programmers can understand what you did without learning everything about your specific solution.
Also, Spring injection can do things that might fit your needs.
Also also if you are going to use reflection, seriously consider annotations so that you aren't tying your functionality to what should be simple arbitrary attribute names.