I am trying to get the correct JSON for
public class MyTestResponse {
#XmlElementWrapper(name = "data")
#XmlElement(name = "values")
public List<String> test = Arrays.asList("Sidney");
}
I now get
"values": [
"Sidney"
],
instead of
"data":{
"values": [
"Sidney"
]
},
So the wrapper element "data" is not present.
I am using com.fasterxml.jackson stack (2.8.6) inside ServiceMix 7 M3.
My JSON provider extends com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider:
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
#Provider
#Consumes({ MediaType.APPLICATION_JSON, "text/json" })
#Produces({ MediaType.APPLICATION_JSON, "text/json" })
public class JsonProvider extends JacksonJaxbJsonProvider {
public JsonProvider() {
super();
ObjectMapper mapper = new ObjectMapper();
AnnotationIntrospector primary = new JaxbAnnotationIntrospector(mapper.getTypeFactory());
AnnotationIntrospector secondary = new JacksonAnnotationIntrospector();
AnnotationIntrospector pair = AnnotationIntrospector.pair(primary, secondary);
mapper.setAnnotationIntrospector(pair);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.disable(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED);
mapper.disable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
this.setMapper(mapper);
}
}
How can I tell the JacksonJaxbJsonProvider to render the wrapper element around the values element?
Related
I am using Immutables library (https://immutables.github.io).
My class looks as follows:
package com.abc.myservice.data.models;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;
import java.util.Map;
import java.util.Optional;
#Value.Immutable
#JsonSerialize(as = ImmutableMyEntityModel.class)
#JsonDeserialize(as = ImmutableMyEntityModel.class)
public interface MyEntityModel {
String myEntityId();
String status();
Optional<Integer> count();
Optional<Integer> version();
Optional<Map<String, String>> attributes();
}
I build the immutable class object with:
ImmutableMyEntityModel.builder()
.myEntityId("some-id")
.status("some-status")
.count(Optional.of(10))
.build()
And my output is:
{
"MyEntityId": "some-id",
"status": "some-status",
"count": {
"present": true
},
"version": {
"present": false
},
"attributes": {
"present": false
}
}
Instead what I would like to see is:
{
"MyEntityId": "some-id",
"status": "some-status",
"count": 10
}
How can I make it work like that?
Use the jackson-datatype-jdk8 module so that Jackson properly understands the java.util.Optional type - a pretty good explanation is in this article.
Add jackson-datatype-jdk8 library to your project/classpath, which contains a Jackson module that allows Jackson to properly understand Optionals.
When creating an ObjectMapper, register the Jdk8Module:
ObjectMapper om = new ObjectMapper();
om.registerModule(new Jdk8Module());
Optionally, add #JsonIgnoreProperties(ignoreUnknown = true) to properties or the class itself to avoid serializing Optional.empty() to null values and instead ignore the property completely.
Full example:
public class JacksonOptionalTest
{
public static void main(String... args)
throws Exception
{
ObjectMapper om = new ObjectMapper();
om.registerModule(new Jdk8Module());
Thing thing = new Thing();
thing.name = "John Smith";
thing.count = Optional.of(12);
String s = om.writeValueAsString(thing);
System.out.println(s);
}
#JsonInclude(Include.NON_ABSENT)
#JsonIgnoreProperties(ignoreUnknown = true)
public static class Thing
{
public String name;
public Optional<Integer> count = Optional.empty();
public Optional<Integer> version = Optional.empty();
}
}
The output of this is {"name":"John Smith","count":12}.
I need to receive some message with SOAP so I've generated a few classes by xsd-scheme and maven-jaxb2-plugin like this:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Claim", propOrder = {
"field",
})
public class ClaimType {
#XmlElement(required = true, type = Integer.class, nillable = false)
protected Integer field;
public Integer getField() {
return bpType;
}
public void setField(Integer value) {
this.field= value;
}
}
After receiving message I need to send these to the next one microservice in wrap of HashMap.
I supposed to use ObjectMapper to convert:
//JAXB DTO --> JSON
ObjectMapper objectMapper = new ObjectMapper();
String jsonContent = objectMapper.writeValueAsString(claimType);
map.put("json", jsonContent);
//JSON --> JAXB DTO
ObjectMapper objectMapper = new ObjectMapper();
String json = map.get("json");
ClaimType claimType = objectMapper.readValue(json, ClaimType.class);
But the generated classes are haven't any constructors so I got the exception like "
No creator like default constructor are exists".
What is the best preactice to work with Jaxb Dto? Can I do smth to successful convert these json to object? Thanks in advance!
I've solved my problem by using ObjectMapper MixIn:
import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
#JsonIgnoreProperties(value = {"globalScope", "typeSubstituted", "nil"})
public abstract class JAXBElementMixIn<T> {
#JsonCreator
public JAXBElementMixIn(#JsonProperty("name") QName name,
#JsonProperty("declaredType") Class<T> declaredType,
#JsonProperty("scope") Class scope,
#JsonProperty("value") T value) {
}
}
And the convertation:
import com.fasterxml.jackson.databind.ObjectMapper;
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.addMixIn(JAXBElement.class, JAXBElementMixIn.class);
solution link
I am reading in a rest api that returns a Json file. I need to ignore the "result" and "optionChain" nodes. I am using Spring Boot with Jackson to deal with the mapping of objects.
Thanks in Advance!
For the Json File click here
Here is my Main:
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import java.util.Collections;
#SpringBootApplication
public class OptionsImpliedMovementApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(OptionsImpliedMovementApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
String resourceURL = url;
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(resourceURL, HttpMethod.GET,entity, String.class);
String rawJson = response.getBody();
ObjectMapper mapper = new ObjectMapper();
//need to read in json ignoring root node
}
Since you're already getting JSON response , then would recommend to use
restTemplate.exchange(URL, HttpMethod.GET, requestEntity, MyPOJO.class);
instead of String.class define your own POJO based on JSON response coming as you have attached in file.json.
In a handy way you can generate your POJO against your JSON from : http://www.jsonschema2pojo.org/ quickly and easily.
So it should look like :
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"optionChain"
})
public class MyPOJO {
#JsonProperty("optionChain")
private OptionChain optionChain;
// getters and setters
}
And another one :
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"result",
"error"
})
public class OptionChain {
#JsonProperty("result")
private List<Result> result = null;
#JsonProperty("error")
private Object error;
// getter and setters
}
And other like :
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"expirationDate",
"hasMiniOptions",
"calls",
"puts"
})
public class Option {
#JsonProperty("expirationDate")
private Integer expirationDate;
#JsonProperty("hasMiniOptions")
private Boolean hasMiniOptions;
#JsonProperty("calls")
private List<Call> calls = null;
#JsonProperty("puts")
private List<Put> puts = null;
So once you'll have the response as :
ResponseEntity<MyPOJO> response = restTemplate.exchange(resourceURL, HttpMethod.GET,entity, MyPOJO.class);
Then response.getBody will give the content inside optionChain node which is what you're looking for. You can then normally drill down to whatever node you want as now you have everything in plain java objects and you can ignore whatever you want or use whatever is needed.
Using objectMapper also you can then achieve the same :
ObjectMapper mapper = new ObjectMapper();
MyPojo myPojo= mapper.readValue(rawJson, MyPojo.class);
Quick (performant) and working.
final ObjectMapper objectMapper = new ObjectMapper();
final JsonNode jsonNode = objectMapper.readTree(rawJson);
final JsonNode result = jsonNode.get("optionChain")
.get("result");
final JsonNode firstResult = result.get(0);
final YourResultClass resultObject = objectMapper.treeToValue(firstResult, YourResultClass.class);
If you need to ignore unknown fields
final ObjectMapper objectMapper =
new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
I have a json payload and an xml payload, and I want to map both of the payloads into one POJO class. One endpoint returns a json and the other a xml. Can i combine both into one pojo class.
{
"house": 'big',
"has-large-house": "yes"
}
<completed-houses>
.....
</completed-houses>
public PayloadResponse(
#JsonProperty("house") final String house,
#JsonProperty("has-large-house") final String hasLargeHouseList,
#XmlElement(name="completed-houses") final String completeHouses) {
this.house = house;
this.hasLargeHouseList = hasLargeHouseList;
this.completeHouses = completeHouses;
}
and then getters and setter for these properties.
Yes! You can combine Jackson and JAXB annotations in the same POJO, using the Jackson module for JAXB annotations so that Jackson can understand JAXB annotations, and jackson-dataformat-xml for serializing to XML.
Here is an example:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.xml.bind.annotation.XmlElement;
import java.io.IOException;
import java.io.StringWriter;
#Data
#NoArgsConstructor
public class PayloadResponse {
private String house;
#JsonProperty("has-large-house")
private boolean largeHouse;
#XmlElement(name = "completed-houses")
private String completedHouses;
public static void main(String[] args) throws IOException {
ObjectMapper xmlMapper = new XmlMapper();
JaxbAnnotationModule module = new JaxbAnnotationModule();
xmlMapper.registerModule(module);
PayloadResponse response = new PayloadResponse();
response.setHouse("The White House");
response.setLargeHouse(true);
response.setCompletedHouses("1600 Pennsylvania Ave.");
StringWriter stringWriter = new StringWriter();
// Serialize value as XML.
xmlMapper.writeValue(stringWriter, response);
System.out.println("XML=" + stringWriter);
// Serialize value as JSON.
ObjectMapper jsonMapper = new ObjectMapper();
stringWriter.getBuffer().setLength(0);
jsonMapper.writeValue(stringWriter, response);
System.out.println("JSON=" + stringWriter);
}
}
Outputs the following:
XML=<PayloadResponse>
<house>The White House</house>
<has-large-house>true</has-large-house>
<completed-houses>1600 Pennsylvania Ave.</completed-houses>
</PayloadResponse>
JSON={"house":"The White House",
"completedHouses":"1600 Pennsylvania Ave.",
"has-large-house":true}
I am trying to get the correct JSON for
public class MyTestResponse {
#XmlElementWrapper(name = "data")
#XmlElement(name = "values")
public List<String> test = Arrays.asList("Sidney");
}
I now get
"data": [
"Sidney"
],
instead of
"data":{
"values": [
"Sidney"
]
},
I am using org.codehaus.jackson stack (1.9.0) inside ServiceMix 7 M3.
My JSON provider extends org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider:
import org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider;
import org.codehaus.jackson.map.AnnotationIntrospector;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector;
import org.codehaus.jackson.xc.JaxbAnnotationIntrospector;
public class MyJsonProvider extends JacksonJaxbJsonProvider {
public JsonProvider() {
super();
ObjectMapper mapper = new ObjectMapper();
AnnotationIntrospector primary = new JaxbAnnotationIntrospector();
AnnotationIntrospector secondary = new JacksonAnnotationIntrospector();
AnnotationIntrospector pair = new AnnotationIntrospector.Pair(secondary, primary);
mapper.getDeserializationConfig().setAnnotationIntrospector(pair);
mapper.getSerializationConfig().setAnnotationIntrospector(pair);
this.setMapper(mapper);
}
}
How can I tell the JacksonJaxbJsonProvider not to replace the XmlElement name but tow wrap it?
As you have discovered JSON marshalling doesn’t honor JAXB annotations. Enable the following MapperFeature on your jackson ObjectMapper (your instance named mapper)
mapper.enable(MapperFeature.USE_WRAPPER_NAME_AS_PROPERTY_NAME);