I am working on a Springboot project and fetching data from Rest API. The response is in XML format and I am facing difficulty while converting it to JSON
XML Response:
<StoreInfo>
<Store Number="1" NCPDPID="0411"/>
<Store Number="3" NCPDPID="1132"/>
<Store Number="4" NCPDPID="0407"/>
</StoreInfo>
The JSON classes I've created are:
public class IDResponse {
private List<IDInfo> StoreInfo;
}
public class IDInfo {
private List<Store> Store;
}
public class Store {
private Integer Number;
private String ID;
}
Code to fetch and convert:
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
ResponseEntity<String> response = restTemplate.exchange(requestUrl,
HttpMethod.GET, entity,
String.class);
XmlMapper xmlMapper = new XmlMapper();
responseData = xmlMapper.readValue(response, IDInfo.class);
The exception I am getting:
Method threw
'com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException'
exception.
Unrecognized field "Store" (class
com.walmart.datamodel.location.IDResponse), not marked as ignorable
How to fix this?
The uppercase names shouldn't be used in the Java classes.
Number and Id are attributes so you should use Annotatiaons to guide jackson:
Root
#JacksonXmlRootElement(localName = "StoreInfo")
public class IDResponse {
#JacksonXmlProperty(localName = "Store")
#JacksonXmlCData
#JacksonXmlElementWrapper(useWrapping = false)
private List<Store> storeInfo;
public List<Store> getStoreInfo() {
return storeInfo;
}
public void setStoreInfo(List<Store> storeInfo) {
this.storeInfo = storeInfo;
}
}
Store Element
public class Store {
#JacksonXmlProperty(localName="Number")
private Integer number;
#JacksonXmlProperty(localName="NCPDPID")
private String id;
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
IDInfo-class isn't needed.
Related
I am using SpringBoot and trying to deserialize JSON like:
{
"userId": "Dave",
"queryResults": {
"id": "ABC",
"carData": {.....},
"carId": "Honda",
"status": 0,
"model": "X"
}
}
, into MyRequestModel clas:
public class MyRequestModel {
private String userId;
private String: queryResults;
}
, that is received as #RequestBody parameter in my #PostMapping method that looks like:
#PostMapping
public String postDate(#RequestBody MyRequestModel data) {
...
return "posted";
}
The above queryResults field is supposed to be stored as a CLOB in a database.
Problem I am having is that if I send this JSON to hit my endpoint (PostMapping) method, it cannot deserialize it into MyRequestModel and I get this error:
Cannot deserialize instance of java.lang.String out of START_OBJECT token
at [Source: (PushbackInputStream); line: 3, column: 18] (through reference chain: MyRequestModel["queryResults"])]
I guess the real answer to your question is: if you NEED the queryResults property to be a String, then implement a custom deserializer.
If not, then, use one of the alternatives that Jonatan and Montaser proposed in the other answers.
Implementing a custom deserializer within Spring Boot is fairly straightforward, since Jackson is its default serializer / deserializer and it provides a easy way to write our own deserializer.
First, create a class that implements the StdDeserializer<T>:
MyRequestModelDeserializer.java
public class MyRequestModelDeserializer extends StdDeserializer<MyRequestModel> {
public MyRequestModelDeserializer() {
this(null);
}
public MyRequestModelDeserializer(Class<?> vc) {
super(vc);
}
#Override
public MyRequestModel deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonNode node = p.getCodec().readTree(p);
String userId = node.get("userId").asText();
String queryResults = node.get("queryResults").toString();
MyRequestModel model = new MyRequestModel();
model.setQueryResults(queryResults);
model.setUserId(userId);
return model;
}
}
Second, mark your class to be deserialized using your custom deserializer by using the #JsonDeserialize annotation:
MyRequestModel.java
#JsonDeserialize(using = MyRequestModelDeserializer.class)
public class MyRequestModel {
private String userId;
private String queryResults;
}
It's done.
queryResults is a String on Java side but it is an Object on JSON side.
You will be able to deserialize it if you send it in as a String:
{
"userId": "Dave",
"queryResults": "foo"
}
or if you create classes that maps to the fields:
public class MyRequestModel {
private String userId;
private QueryResults queryResults;
}
public class QueryResults {
private String id;
private CarData carData;
private String carId;
private Integer status;
private String model;
}
or if you serialize it into something generic (not recommended):
public class MyRequestModel {
private String userId;
private Object queryResults;
}
public class MyRequestModel {
private String userId;
private Map<String, Object> queryResults;
}
public class MyRequestModel {
private String userId;
private JsonNode queryResults;
}
You have two options to deserialize this request:-
change the type of queryResults to Map<String, Object>, it will accepts everything as an object of key and value. (Not recommended)
public class MyRequestModel {
private String userId;
private Map<String, Object> queryResults;
}
You have to create a class that wraps the results of queryResults as an object.
class QueryResult {
private String id;
private Map<String, Object> carData;
private String carId;
private Integer status;
private String model;
public QueryResult() {}
public QueryResult(String id, Map<String, Object> carData, String carId, Integer status, String model) {
this.id = id;
this.carData = carData;
this.carId = carId;
this.status = status;
this.model = model;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Map<String, Object> getCarData() {
return carData;
}
public void setCarData(Map<String, Object> carData) {
this.carData = carData;
}
public String getCarId() {
return carId;
}
public void setCarId(String carId) {
this.carId = carId;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
}
and make the type of queryResult as shown:-
public class MyRequestModel {
private String userId;
private QueryResult queryResults;
}
I am new to springboot, i am getting a response as below in my json response:
"Number": "08002050"
I have defined it as String in my spring boot app.
I want to get a response as below:
"Number": 08002050
How do i accomplish this. please help
You can manage it in server side with a tricky way.
public class User {
private int id;
private String name;
#JsonIgnore // ignore this field when serialize
private String number;
#JsonProperty(value = "number") // change name of field when serialize
private int intValueOfNumber;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public int getIntValueOfNumber() {
return Integer.parseInt(number); // parse number string to int
}
public void setIntValueOfNumber(int intValueOfNumber) {
this.intValueOfNumber = intValueOfNumber;
}
}
In this entity #JsonIgnore annotation is ignore your field for JSON serialization and pass intValueOfNumber as int to JSON. Your json will be following:
{"id":1,"name":"Java","number":44124}
You may lost zero suffix of number string when you parse it to int.
i don't know what or if i'm doing it wrong, but the conversion from json to my POJOs just don't work. I'm with the dependencies updated. When i called the method "readJSONFromURL" my return always is the object with yours attributes with value NULL. All the libs are up to date. My Objects:
public class ListHall {
private List<Hall> Hall;
public void setHall(List<Hall> hall) {
this.Hall = hall;
}
public List<Hall> getHall() {
if (Hall == null) {
this.Hall = new ArrayList<Hall>();
}
return Hall;
}
}
public class Hall {
private String id;
private String name;
private Integer count;
//getter and setters here
}
My DataMappers:
data_mapper ListHall:ListHallMapper
data_mapper Hall:HallMapper
My method conversor:
public ListHall mapHall() throws IOException {
ListHallMapper returnListHallMapper = new ListHallMapper();
HallMapper hallMapper = new HallMapper();
DataMapper.createContext(Arrays.asList(returnListHallMapper,
hallMapper),
(DataMapper mapper) -> {
mapper.setReadKeyConversions(Arrays.asList(DataMapper.CONVERSION_CAMEL_TO_SNAKE));
});
return returnListHallMapper.readJSONFromURL("http://192.168.0.16:7080/integration/hall", ListHall.class,"/ListHall");
}
My output JSON:
{"ListHall":{"Hall":[{"id":"0","name":"Salão 1","count":"10"},{"id":"f6a495c1-be5e-4476-a362-5d42e572bfae","name":"Salão 3","count":"0"}]}}
My result:My LIB:
What i'm doing it wrong?
I am implementing a generic java POJO wrapper for jqGrid consumption, using JAXB and JSON. This is a CXF service so my marshaller libraries of choice are either Jettison or Jackson:
#XmlRootElement(name = "response")
public class JQGridResponseWrapper<T> {
private PaginatedResults<T> results;
public JQGridResponseWrapper() {
}
public JQGridResponseWrapper(PaginatedResults<T> results) {
this.results = results;
}
#XmlElementWrapper(name = "records")
#XmlElement(name = "record")
public List<T> getRecords() {
return results.getRecords();
}
#XmlElement(name = "pager")
public Pager getPager() {
return results.getPager();
}
}
Here's a sample POJO to be wraped by the generic wrapper:
#XmlRootElement
public class Note {
private Long id;
private String subject;
private String description;
private Project project;
public Note() {}
public Note(Long id, String subject, String description, Project project) {
this.id = id;
this.subject = subject;
this.description = description;
this.project = project;
}
#XmlElement(name="noteId")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Project getProject() {
return project;
}
public void setProject(Project project) {
this.project = project;
}
}
When marshaling to XML, everything works fine, all types are correctly mapped, and I get a parent <records> element containing an array of <record> elements. But when marshaling to JSON (the project requirement), the 'record' element is unnamed, which makes jqGrid choke:
{"records":[
{"subject":"subject aaa",
"description":"Description dsifj ofdisjo",
"project":{
"projectCode":"HWIIA",
"description":"project description",
"brand":null,
"projectId":101
},
"noteId":201
},
{"subject":"subject bbb",
"description":"Description odisfj doisjf odsijf",
"project":{
"projectCode":"HWIIA",
"description":"project description",
"brand":null,
"projectId":101
},
"noteId":202
},
{"subject":"subject ccc",
"description":"Description oijgf gfoij jgifif",
"project":{
"projectCode":"HWIIA",
"description":"project description",
"brand":null,
"projectId":101
},
"noteId":203
}
],
"pager"{
"recordsPerPage":10,
"currentPage":1,
"fromRecord":1,
"toRecord":3,
"totalRecords":3,
"totalPages":1}}
I need to get a name for each record in the records array. Is there a simple way to make this work, either with Jettion or Jackson? I searched and searched the web but couldn't find a straighforward solution for my target marshaler libraries. I did see some answers for MOXY, but it is problematic for me to change libraries at this point. Any help greatly appreciated.
So my entities look like this:
public class HappyClass<T>
{
private String id;
prviate int ver;
private Object obj;
public String getId()
{
return this.id;
}
public void setId( String id )
{
this.id = id;
}
public int getVer()
{
return this.ver;
}
public void setVer( int ver )
{
this.ver = ver;
}
#JsonTypeInfo( use = Id.NONE )
public T getObj()
{
return obj;
}
public void setObj( T obj )
{
this.obj = obj;
}
}
public class HappyGeneric
{
private String someStuff();
public String getSomeStuff()
{
return this.someStuff();
}
public void setSomeStuff( String someStuff )
{
this.someStuff = someStuff;
}
}
If I instantiate a class like this:
HappyClass<HappyGeneric> hc = new HappyClass<HappyGeneric>();
If I send it to Spring in a #ResponseBody it returns this:
{
"id" : "iamsomeid",
"ver" : 123,
"obj" : {
"someStuff" : "iamsomestuff"
}
}
However, when Spring and/or Jackson attempts to unmarshal the same JSON, it figures out that the main class is a HappyClass, however, the getObj() it unmarshals to a LinkedHashMap and not a HappyGeneric no matter what I seem to annotate it with.
Anybody have any ideas how I can force Jackson to unmarshal that generic to the original class?
Thanks!
EDIT: I'm aware I can call mapper.convertValue( blah.getObj(), HappyGeneric.class ) and get the object out that way-- I was hoping to get Spring to figure it out automatically (through annotations, for example).