I have the following Object:
public class Class_a{
private List<class_b> someList;
}
public class Class_b{
private Map<String,String> someMap;
}
My json will look like this:
"someList":[{"someMap":{"strKey1":"strValue1"}},{"someMap":{"strKey2":"strValue2"}}]
Is it possible to serialize a Json that will look like this, without changing my Objects (and I will have the option to deserialize the Object):
"someList":[{"strKey1":"strValue1"},{"strKey2":"strValue2"}]
*I know that if will defined my object like this:
public class Class_a{
private List<Map<Strung,String>> someList;
}
i will get a Json like I want - but I am trying to find more elegant solution then 'list' that contain a 'map'
My project use spring framework and Jackson.
This worked for me I only had to add getters and setters to your classes and I was able to parse with jackson:
#Test
public void t() throws IOException {
String json = "{\"someList\":[{\"someMap\":{\"strKey1\":\"strValue1\"}},{\"someMap\":{\"strKey2\":\"strValue2\"}}]}";
Class_a a = new ObjectMapper().readValue(json, Class_a.class);
System.out.println(a);
}
#Getter
#Setter
public class Class_a{
private List<Class_b> someList;
}
#Getter
#Setter
public class Class_b{
private Map<String,String> someMap;
}
I'm using lombok but that's nothing special, you can create the getters/setters manually too and will work
Related
I'm using jackson csv to parse a csv as pojo
ID,requestId,requestSource,documentIds,trackingIds
documentIds,123456,CLAIMS,123456;223456,
->
#Data
#NoArgsConstructor
#JacksonXmlRootElement(localName = "triggerDocumentExport",namespace = Connection.NAMESPACE_CAS)
public class TriggerDocumentExport {
private Wrapper in;
public TriggerDocumentExport(Wrapper in){this.in = in;}
#Data
public static class Wrapper{
private String requestId,
requestSource;
private List<String> documentIds,
trackingIds;
}
}
I want documentIds to be parsed as a List<String>, with default ArrayElementSeparator(which is ;)
but it keeps parsing it as a single string "123456;223456"
without DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, I got an exception
with the configuration, I got a List with only one element "123456;223456"
If I don't make mistake, should jackson csv support semicolon-seperated list by default?Or there's something I've misunderstood.
I am using Jackson Mixin to deserialize mongo object and the Mixin looks as below.
public interface MyMixin {
/**
* Mixin to set key value for pojo.
* #param key key
* #param value value
*/
#JsonAnySetter
void put(String key, Object value);
}
The mixin works really well for all fields including list except for the id field.
The pojo looks as below.
public class MyPojo {
#JsonProperty("_id")
#javax.persistence.Id
private String id;
private String name;
}
The exception
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of java.lang.String out of START_OBJECT token
at [Source: (String)"{"_id": {"$oid": "5e049cb30eb7811fec0c7029"}
I understand that its failing to deserialize string from a nested json.
One way through which I solved the problem is via writing custom mapper
public static MyPojo map(final Document document) {
final MyPojo pojo = new MyPojo();
pojo.setUd(document.getObjectId("_id").toHexString());
// set other fields
return pojo;
But this requires change is mapper whenever there is a change in pojo, adding/removing fields.
The Mixin works without any change, How shall I update my Mixin to handle objectId as well?
I am not sure if you can have a mixin to handle this kind of case in a generic way. I propose a solution that has not much to do with mixin but gives one generic way to deserialize such fields. First create a class to represent the json id:
#Getter #Setter
public class OidId {
#JsonProperty("$oid")
private String oid;
}
Then an abstract class to have the mapping stuff:
public abstract class HasOidId {
// moved from MyPojo
#JsonProperty("_id")
#javax.persistence.Id
private String id;
#JsonSetter("_id") // this is the trigger for mapping "_id" stufff
public void setId(OidId oidId) {
this.id = oidId.getOid();
}
}
Then let MyPojo extend above:
#Getter #Setter
public class MyPojo extends HasOidId {
private String name;
}
Given the following classes and a mapper that takes mulitple source arguments
(I use lombok to keep source as short as possible.)
#Getter
#Setter
public class MySourceOne {
private String src1;
}
#Getter
#Setter
public class MySourceTwo {
private String src2;
}
#Getter
#Setter
public class MyTargetObject {
private String prop1;
private String prop2;
}
#Mapper
public interface MyTargetObjectMapper {
#Mapping(target="prop1", source="a")
#Mapping(target="prop2", source="b")
public MyTargetObject mapMyObject(String a, String b);
}
#Getter
#Setter
public class MyComplexTargetObject {
private MyTargetObject myTargetObject;
}
I am trying to create a mapper for MyComplexTargetObject that will invoke implicitly the MyTargetObjectMapper .
But the "source" won't allow to map multiple parameter like this
#Mapper(uses= {MyTargetObjectMapper.class})
public interface MyComplexTargetObjectMapper {
#Mapping(target="myTargetObject", source="one.src1, two.src2")
public MyComplexTargetObject convert(MySourceOne one, MySourceTwo two);
}
So I am trying to use an expression="..." instead of source, but nothing works so far.
Any thoughts a clean way to do this without calling the MyTargetObjectMapper in a concrete method?
MapStruct does not support selection of methods with multiple sources.
However: you can do target nesting to do this.
#Mapper
public interface MyComplexTargetObjectMapper {
#Mapping(target="myTargetObject.prop1", source="one.src1" )
#Mapping(target="myTargetObject.prop2", source="two.src2")
public MyComplexTargetObject convert(MySourceOne one, MySourceTwo two);
}
And let MapStruct take care of generating the mapper. Note: you can still use a MyComplexTargetObjectMapper to do single source to target to achieve this.
I'm using jackson (with spring boot) to return some DTOs like json. The problem is that I have specific DTO which contains nested objects, which contains another objects. Can I have ignore some nested properties directly from the DTO, without any Annottations on the nested objects (because they are used in another DTOs)
public class MyDTO {
private MyObjectA a;
}
public class MyObjectA a {
private MyNestedObject b;
}
I want when i serialize MyDTO to exclude MyNestedObject b
I've tried with #JsonIgnoreProperties, but it not works with nested objects.
Can I achieve this mission only with Annotations in the MyDTO class?
You might use #JsonView. You need to annotate some nested objects but it is not kind a static thing that then hides everything from other DTOs or so.
For example you could declare following views to use:
public class View {
public static class AllButMyNestedObject {
}
public static class AlsoMyNestedObject
extends AllButMyNestedObject {
}
}
Then annotating your classes like:
#JsonView(AllButMyNestedObject.class)
public class MyDTO {
private MyObjectA a;
}
and
public class MyObjectA {
#JsonView(AlsoMyNestedObject.class)
private MyNestedObject b;
}
you can decide with mapper what to serialize, like:
ObjectMapper mapper = new ObjectMapper();
String result = mapper
.writerWithView(View.AlsoMyNestedObject.class)
// OR .writerWithView(View.AllButNestedObject.class)
.writeValueAsString(myDto);
So I have json file like:
{ "id" : 1,
"includingJson" : {"foo" : "bar"}
}
And I have some DTO like:
...
public class SubscriptionDTO extends AbstractDTO{
private Long id;
private JsonNode includingJson;
But after I try convert JSON to POJO, by code
public static <T> T jsonStringToDto(Class<?> dtoClass, String jsonContent) {
ObjectMapper mapper = new ObjectMapper();
try {
return (T) mapper.readValue(jsonContent, dtoClass);
} catch (IOException e) {
log.error(e);
}
return (T) new Object();
}
I've got error message Can not construct instance of org.codehaus.jackson.JsonNode, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
So the main problem - how I can fix this?
It seems that you imported wrong JsonNode, which is older. Proper class to use is com.fasterxml.jackson.databind.JsonNode, and it works. Tested it with Jackson 2.8. Also to ensure proper work it's best if DTO classes have getters, setters, and no-arg constructors. So, update the version.
You can edit your DTO to look like this:
public class SubscriptionDTO extends AbstractDTO{
private Long id;
private InnerDTO includingJson;
//..getters, setters
}
And you InnerDTO class:
public class InnerDTO extends AbstractDTO{
private String foo;
//..getters, setters
}