I'm using jackson and I have a problem with the method returning the Object object. This means that different classes can be passed in .json file and I want to parse them to the corresponding object from my project.
#XmlAnyElement (lax = true)
public Object getEntity() {
return this.entity;
}
I always get LinkedHashMap in return since JSON isn't sure what object should it expect.
Is it possible to annotate the method with the list of expected class names?
Is it possible to annotate the method with the list of expected objects that should be returned?
Related
I am getting a list of objects from 3rd party but it will always contain one object only. So at my end in target I have created it as an object rather than list. That object contains multiple lists inside it just like source object.
This is how I am trying to map a list to an object. ChargeTransaction contain orderInvoice as an object and not a list. For list which are inside ChargeTransaction I have created separate mappers. I dont want to write java code in #afterMapping because then how nested lists will be mapped. The nested lists are of type in both the objects.
#Mapping(target = "orderInvoice", source = "basePaymentRequest.invoice.eventPayload.orderInvoices")
ChargeTransaction createInvoiceCTMapper(PaymentTriggerBaseModel basePaymentRequest, ChargeType chargeType);
Error
java: Can't map property "List<OrderInvoice> basePaymentRequest.invoice.eventPayload.orderInvoices" to "OrderInvoice orderInvoice". Consider to declare/implement a mapping method: "OrderInvoice map(List<OrderInvoice> value)".
I tried
#Mapping(target = "orderInvoice", expression= "java(basePaymentRequest.invoice.eventPayload.orderInvoices.get(0))")
But it gives error in Impl class
chargeTransaction.setOrderInvoice( basePaymentRequest.invoice.eventPayload.orderInvoices.get(0) );
java: incompatible types: com.sams.oms.ng.common.models.payment.request.OrderInvoice cannot be converted to com.sams.oms.ng.common.models.payment.cosmos.OrderInvoice
IMHO the best way to solve this problem is to use a #Named paired with #Mapping#qualifiedByName
#Mapper
class Mapper {
#Mapping(target = "orderInvoice", source ="basePaymentRequest.invoice.eventPayload.orderInvoices", qualifiedByName="firstElement")
ChargeTransaction createInvoiceCTMapper(PaymentTriggerBaseModel basePaymentRequest, ChargeType chargeType);
#Named("firstElement")
OrderInvoice map(List<OrderInvoice> value) {
if(value == null) return null;
if(value.isEmpty()) return null;
return map(value.get(0));
}
abstract com.sams.oms.ng.common.models.payment.request.OrderInvoice map(com.sams.oms.ng.common.models.payment.cosmos.OrderInvoice invoice);
}
In this way you are instructed MapStruct to use map(List<>) to convert invoices to a single OrderInvoice and abstract map(OrderInvoice) to let MapStruct autogenerate mapping code.
Code in untested because I haven't limited spare time today,but I hope my example may be useful;if anything is wrong feel free to comment and I will correct code asap.
Can someone please help in deserializing xml string : List<A> to Object.class using jackson in java.Xml looks like :
<list> <A><id>1</id><name>Jeff</name> <id>2</id><name>John</name> </A>
It returns a HashMap object if I convert it to Object.class . I have created a utility function XMLToObject which returns Object class. This will be typcasted on the caller function end to get the required type of Object.
public Object XMLtoObject(String xml){
return mapper.readValue(xml,Object.class)
}
But if I use List.class in place of Object.class it deserializes it to list of hashmaps.
public Object XMLtoObject(String xml){
return mapper.readValue(xml,List.class)
}
I am looking a way to convert it into Object.class which I can typecast on caller function . Is that possible in jackson ? I know we can do it through xstream
The problem with List.class is that it doesn't have any information about its elements. You need one of the overloaded readValue methods. For instance, using TypeReference:
return mapper.readValue(xml, new TypeReference<List<Object>>() {});
This creates an anonymous sub class of TypeReference, from which the complete generic type (List<Object>) can be read by Jackson. The result should therefore be a List<Object> instead of a List<HashMap>.
When I create a custom hibernate Type, such as
public class CustomHibernateType extends AbstractSingleColumnStandardBasicType<Custom>
{
public CustomHibernateType()
{
// Notice the JsonBinarySqlTypeDescriptor class from #vladmihalcea's hibernate types library
super(JsonBinarySqlTypeDescriptor.INSTANCE, CustomHibernateTypeDescriptor.INSTANCE);
}
#Override
public String getName()
{
return "CustomHibernateType";
}
}
And create the Type Descriptor
// only constructor for brevity, can include more if needed
public CustomHibernateTypeDescriptor()
{
super(Custom.class, ImmutableMutabilityPlan.INSTANCE);
}
I find that when I am saving and retrieving data in my custom hibernate type descriptor, the class type used is different. It is saved as a jackson JsonNode, which is expected as this is what is used in the JsonBinarySqlTypeDescriptor class, however when it is retrieved it is retrieved in the unwrap method as a PGobject (which has a simple string value).
Should I be expecting this, or should I be expecting JsonNode in both directions? I have no problems processing the PGobject, it just wasn't expected so I'm wondering if there is some config missing somewhere.
The wrap method transforms the entity attribute type to the one that should be passed to the JDBC PreparedStatement.
The unwrap method transforms the object that was extracted from the JDBC ResultSet to the expected entity attribute type.
We have a class containing multiple Sets of Longs. We want them serialized as arrays, and most clients do so.
However, we have a PHP client that creates sets such that they serialize in an odd way. A set with the number 4 comes in like this:
"setOfNumbers": {
"4": 0
},
Naturally, Jackson complains about this being an object and not an array. What I would like is to have a custom deserializer that is only invoked if Jackson detects an object where a Set<Long> should be (and ideally only if they are contained in specific classes.)
I've tried this:
this.addDeserializer(Set.class, new StdDelegatingDeserializer<>(new StdConverter<Map<String, Long>, Set<Long>>() {
#Override
public Set<Long> convert(Map<String, Long> set) {
return parseLongs(set);
}
}));
The problem with this is that now it expects an object instead of an array for all Set fields. The class being deserialized is generated, so I can't add any annotations or make other changes.
If the generated class has always the same name you can try with Json Jackson Mix-in annotations as shown in this example
Is there a way to modify the field of POJO with new property(like using MixIns or #JSONProperty) and get the modified POJO back ? (A way to add/modify field of a POJO dynamically ?)
Like I have a class
class PojoA<T>{
private T data;//field to be modified as NewData
}
So, I tried with MixIns like
public interface PojoMixIn<T> {
#JsonProperty("NewData")
T getData();
}
Now to get the modified field, I use ObjectMapper
mapper.addMixInAnnotations(PojoA.class,PojoMixIn.class);
mapper.writerWithDefaultPrettyPrinter().writeValueAsString(pojoA);
The actual result is a String, but can I be able to get the modified POJO?