Map Java field to JSON document root - java

I couldn't find an example how to map the following json:
{
"id":1,
"name":"hugodesmarques",
"age":30,
}
To the following java object using jackson:
public class EntityDto {
private Map<String, Object> content;
}
Notice the dto is just a wrapper. What I'm trying to achieve is to have an object EntityDto with a Map{name=>"hugodesmarques", age=>30, id=>1}.
I want to avoid having to map each json field to an object map.

A step back
First of all, the JSON you posted in you question is invalid: there's a comma after 30 and it shouldn't be there. Fix your JSON otherwise Jackson won't parse it:
{
"id": 1,
"name": "hugodesmarques",
"age": 30
}
Parsing the JSON with Jackson
Add a constructor annotated with #JsonCreator to the EntityDto class, as following:
public class EntityDto {
private Map<String, Object> content;
#JsonCreator
public EntityDto(Map<String, Object> content) {
this.content = content;
}
// Getters and setters omitted
}
Then parse the JSON using ObjectMapper:
String json = "{\"id\":1,\"name\":\"hugodesmarques\",\"age\":30}";
ObjectMapper mapper = new ObjectMapper();
EntityDto entityDto = mapper.readValue(json, EntityDto.class);

Structure of class must be like structure of JSON:
public class EntityDto {
int id;
String name;
int age;
}

Jackson can read JSON as a HashMap:
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> map = mapper.readValue("{\"id\":1, \"name\": \"One\"}", HashMap.class);
EntityDto dto = new EntityDto();
dto.setContent(map);

Related

How to ignore JSON properties similar to #JsonIgnore in Deserialization

I have a JSON object similar below:
[
{
"objA": {
"propA": "AAAA",
"propB": "BBBB",
"objB": {
"objC": {
"propC": "CCCC",
"propD": "DDDD"
}
},
"objD": [
"asa"
],
"propE": "AW",
"propF": "533",
"propG": "ABW",
"propH": "ARU",
"objE": {
"objF": {
"propI": "SASDS",
"propJ": "54DEFF"
}
}
}
}
]
When I deserialize this JSON into a List, I would like to do for part of this object, for example: I would like to ignore objB, objC, objD, objE and objF.
To do that I has been used the #JsonIgnore annotation. So I did something like that:
public class MyClass {
// objects and properties not ignorabled
private ClassA objA;
private String propE;
private String propF;
private String propG;;
private String propH;
// objects ignorabled in deserialization
#JsonProperty("objB")
#JsonIgnore
private Object objB;
#JsonProperty("objD")
#JsonIgnore
private Object objD;
#JsonProperty("objE")
#JsonIgnore
private Object objE;
/** gets and setters here **/
Follow below the piece of code that deserialize my JSON
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(url, new TypeReference<List<MyClass>>(){});
This code is working. this code is ignoring the objects from JSON, but I believe there are some another way to do that instead of use #JsonIgnore to each object or property in my entity.
Do you know how can I do that better?
Do you want to avoid using # notations ?
If not, have you tried using a filter like #JsonFilter("myFilter") in Jackson ? As described here: https://www.baeldung.com/jackson-ignore-properties-on-serialization
See also https://www.tutorialspoint.com/jackson_annotations/jackson_annotations_jsonfilter.htm
So you would have to write:
#JsonFilter("myFilter")
public class MyClass { ... }
in your class. Then do something like:
SimpleBeanPropertyFilter objBFilter = SimpleBeanPropertyFilter
.serializeAllExcept("objB");
SimpleBeanPropertyFilter objDFilter = SimpleBeanPropertyFilter
.serializeAllExcept("objD");
SimpleBeanPropertyFilter objEFilter = SimpleBeanPropertyFilter
.serializeAllExcept("objE");
FilterProvider filters = new SimpleFilterProvider()
.addFilter("objBFilter", theFilter)
.addFilter("objDFilter", theFilter)
.addFilter("objEFilter", theFilter);

Jackson: Deserialize JSON array from JSON object into Java List

I have been stumbled by this for a while. I have a Spring application and would like to parse the following JSON:
{
"metadata": {...}
"response": {
"objects": [
{
"name": "someName",
"properties": [<array_of_properties>]
},
...
]
}
}
into a list of the following Java objects:
public class MyClass {
String name;
List<CustomProperties> customProperties;
}
Meaning, I want to extract only the objects array and parse only that. I have tried using a custom deserializer and that works, but I had to do:
#JsonDeserialize(using=MyDeserializer.class)
public class MyClassList extends ArrayList<MyClass>{}
and then:
ObjectMapper objectMapper = new ObjectMapper();
List<MyClass> list = objectMapper.readValue(json, MyClassList.class)
Is there anyway to avoid extending ArrayList, since currently I am doing that in order to be able to access the .class property.
you can define your json structure with a couple of classes
public class MyJson {
private MyResponse response;
...
}
public class MyResponse {
private List<MyClass> objects;
...
}
public class MyClass {
String name;
List<CustomProperty> customProperties;
...
}
than you can use Jackson to parse the json string to MyJson class, no special #JsonDeserialize is needed
ObjectMapper objectMapper = new ObjectMapper();
MyJson myJson = objectMapper.readValue(json, MyJson.class);
List<MyClass> list = myJson.getResponse().getObjects();
Keep in mind, this code is only a draft, all classes should have setters (and getters) and some null checks are required
You can do something like this. I feel this would be cleaner
#JsonIgnoreProperties(ignoreUnknown = true)
class Wrapper{
private Response response;
//setters, getters
}
#JsonIgnoreProperties(ignoreUnknown = true)
class Response{
private List<MyClass> objects;
//setters, getters
}
#JsonIgnoreProperties(ignoreUnknown = true)
public class MyClass {
String name;
List<CustomProperties> customProperties;
//setters, getters
}
ObjectMapper objectMapper = new ObjectMapper();
Wrapper wrapper = objectMapper.readValue(json, Wrapper.class)
You can extrat objects and consequently CustomProperties by traversing the list. You can declare only fields which you are interested in and ignore others by #JsonIgnoreProperties(ignoreUnknown = true)(for example i have not included metadata)

Retrieving Java Objects from a json post request

I am developing a restful web application using java and jax-rs. In server side, I have to accept Json type requests as given by the client using POST method.
#POST
#Path("/Request")
#Consumes(MediaType.APPLICATION_JSON)
public String process(SMessage message) throws Exception {
message.getHeader();
message.getBody();
}
The json object have two composite fields like in the below format.
{
"header": {
"serviceType": "A"
},
"body": {
"id": "1",
"name": "abc"
}
}
Based on the serviceType specified in the Header field, the parameters in the body will differ. I need to map this body field in to a java POJO class. The POJO class is not the same for all requests. How can I achieve this effectively?
If you are using Jackson as your JSON parser, a simple way is to declare body to be a JsonNode to handle dynamic keys as follows:
class MyResponse {
private MyHeader header;
private JsonNode body;
//general getters and setters
}
And I assumed that you have already a POJO for header such as:
class MyHeader {
private String serviceType;
//general getters and setters
}
Finally, let's verify that it works:
String responseStr = "{\"header\": {\"serviceType\": \"A\"},\"body\": {\"id\": \"1\",\"name\": \"abc\"}}";
ObjectMapper mapper = new ObjectMapper();
MyResponse myResponse = mapper.readValue(responseStr, MyResponse.class);
System.out.println(myResponse.getBody().get("name").asText());
Console output:
abc
Another way to solve this issue is by using Map and everything else is the same:
class MyResponse {
private MyHeader header;
private Map<String, Object> body;
//general getters and setters
}

Java - Object Mapper - JSON Array of Number to List<Long>

In my front end I send this JSON:
"ids": [ 123421, 15643, 51243],
"user": {
"name": "John",
"email": "john#sovfw.com.br"
}
To my Spring Endpoint below:
#PostMapping(value = "/sendToOficial")
public ResponseEntity<?> sendToOficial(#RequestBody Map<String, Object> payload) {
ObjectMapper mapper = new ObjectMapper();
List<Long> pointsIds = mapper.convertValue( payload.get("pointsIds"), List.class );
UsuarioDTO autorAlteracao = mapper.convertValue(payload.get("user"), UsuarioDTO.class);
for (Long idPoint : pointsIds) { ... }
But I'm getting a Cast Exception in the for saying that it can't cast Integer to Long.
I can't receive the "ids" numbers as Integer, I want to receive as Long.
Please, how could I do this?
First, define POJOs for mapping your request object:
public class RequestObj implements Serializable{
private List<Long> ids;
private UsuarioDTO user;
/* getters and setters here */
}
public class UsuarioDTO implements Serializable{
private String name;
private String email;
/* getters and setters here */
}
And then modify your endpoint:
#PostMapping(value = "/sendToOficial")
public ResponseEntity<?> sendToOficial(#RequestBody RequestObj payload) {
In this way you also do not need to use an ObjectMapper. Just call payload.getIds().
Consider also that in this way if payload changes you'll need only to change RequestObj definition, while using ObjectMapper would force you to update also your endpoint in an important way. It's better and safer to separate payload representation from control logic.
In jackson-databind-2.6.x and onward versions you can configure the ObjectMapper to serialize low typed int values (values that fit in 32 bits) as long values using the DeserializationFeature#USE_LONG_FOR_INTS configuration feature:
#PostMapping(value = "/sendToOficial")
public ResponseEntity<?> sendToOficial(#RequestBody Map<String, Object> payload) {
ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature .USE_LONG_FOR_INTS, true);
List<Long> pointsIds = mapper.convertValue( payload.get("pointsIds"), List.class );
UsuarioDTO autorAlteracao = mapper.convertValue(payload.get("user"), UsuarioDTO.class);
for (Long idPoint : pointsIds) { // ... }
}
If you just want your mapper to read into a List<Long>, use this trick for obtaining full generics type information by sub-classing.
Example
ObjectMapper mapper = new ObjectMapper();
List<Long>listOfLong=mapper.readValue("[ 123421, 15643, 51243]" ,
new TypeReference<List<Long>>() {
});
System.out.println(listOfLong);
Prints
[123421, 15643, 51243]

JSON serialization in Jersey - How to ignore XmlJavaTypeAdapter for serializing a map?

In my Jersey-based REST webservice I need to provide xml and json output. The class Result has a map, annotated with XmlJavaTypeAdapter to correctly serialize it to xml.
#XmlRootElement
public class Result {
private Map<String,Integer> results = new HashMap<String, Integer>();
public Result(){}
#XmlJavaTypeAdapter(ResultMapAdapter.class)
public Map<String,SearchResult> getResults() {
return results;
}
}
The XML output looks like:
<results>
<result><name>Key1</name><value>Value1</value>
<result><name>Key2</name><value>Value2</value>
</results>
And the json output looks like
"result":[{
"name": "Key1",
"value": Value1
},{
"name": "Key2",
"value": Value2
}]
But I want that it looks like:
"result":{
"Key1": Value1,
"Key2": Value2
}
If I remove the XMlRootElement and the XmlJavaTypeAdapter annotation, the json output looks like I wanted, but then the xml serialization failed. Is there a workaround?
One possible solution is the use an custom ObjectMapperProvider. The Following provider doesn't create an combined mapper for json and xml. So the json serialization doesn't use the xml annoatation.
Of course the disadvantage of this sol
#Provider
public class ObjectMapperProvider implements ContextResolver<ObjectMapper> {
final ObjectMapper defaultObjectMapper;
public ObjectMapperProvider() {
defaultObjectMapper = createDefaultMapper();
}
#Override
public ObjectMapper getContext(Class<?> type) {
return defaultObjectMapper;
}
private static ObjectMapper createDefaultMapper() {
ObjectMapper result = new ObjectMapper();
result.configure(Feature.INDENT_OUTPUT, true);
return result;
}
}

Categories

Resources