I have a Java class MyPojo that I am interested in deserializing from JSON. I have configured a special MixIn class, MyPojoDeMixIn, to assist me with the deserialization. MyPojo has only int and String instance variables combined with proper getters and setters. MyPojoDeMixIn looks something like this:
public abstract class MyPojoDeMixIn {
MyPojoDeMixIn(
#JsonProperty("JsonName1") int prop1,
#JsonProperty("JsonName2") int prop2,
#JsonProperty("JsonName3") String prop3) {}
}
In my test client I do the following, but of course it does not work at compile time because there is a JsonMappingException related to a type mismatch.
ObjectMapper m = new ObjectMapper();
m.getDeserializationConfig().addMixInAnnotations(MyPojo.class,MyPojoDeMixIn.class);
try { ArrayList<MyPojo> arrayOfPojo = m.readValue(response, MyPojo.class); }
catch (Exception e) { System.out.println(e) }
I am aware that I could alleviate this issue by creating a "Response" object that has only an ArrayList<MyPojo> in it, but then I would have to create these somewhat useless objects for every single type I want to return.
I also looked online at JacksonInFiveMinutes but had a terrible time understanding the stuff about Map<A,B> and how it relates to my issue. If you cannot tell, I'm entirely new to Java and come from an Obj-C background. They specifically mention:
In addition to binding to POJOs and "simple" types, there is one
additional variant: that of binding to generic (typed) containers.
This case requires special handling due to so-called Type Erasure
(used by Java to implement generics in somewhat backwards compatible
way), which prevents you from using something like
Collection.class (which does not compile).
So if you want to bind data into a Map you will need to use:
Map<String,User> result = mapper.readValue(src, new TypeReference<Map<String,User>>() { });
How can I deserialize directly to ArrayList?
You can deserialize directly to a list by using the TypeReference wrapper. An example method:
public static <T> T fromJSON(final TypeReference<T> type,
final String jsonPacket) {
T data = null;
try {
data = new ObjectMapper().readValue(jsonPacket, type);
} catch (Exception e) {
// Handle the problem
}
return data;
}
And is used thus:
final String json = "";
Set<POJO> properties = fromJSON(new TypeReference<Set<POJO>>() {}, json);
TypeReference Javadoc
Another way is to use an array as a type, e.g.:
ObjectMapper objectMapper = new ObjectMapper();
MyPojo[] pojos = objectMapper.readValue(json, MyPojo[].class);
This way you avoid all the hassle with the Type object, and if you really need a list you can always convert the array to a list by:
List<MyPojo> pojoList = Arrays.asList(pojos);
IMHO this is much more readable.
And to make it be an actual list (that can be modified, see limitations of Arrays.asList()) then just do the following:
List<MyPojo> mcList = new ArrayList<>(Arrays.asList(pojos));
This variant looks more simple and elegant.
//import com.fasterxml.jackson.core.JsonProcessingException;
//import com.fasterxml.jackson.databind.ObjectMapper;
//import com.fasterxml.jackson.databind.type.CollectionType;
//import com.fasterxml.jackson.databind.type.TypeFactory;
//import java.util.List;
CollectionType typeReference =
TypeFactory.defaultInstance().constructCollectionType(List.class, Dto.class);
List<Dto> resultDto = objectMapper.readValue(content, typeReference);
This works for me.
#Test
public void cloneTest() {
List<Part> parts = new ArrayList<Part>();
Part part1 = new Part(1);
parts.add(part1);
Part part2 = new Part(2);
parts.add(part2);
try {
ObjectMapper objectMapper = new ObjectMapper();
String jsonStr = objectMapper.writeValueAsString(parts);
List<Part> cloneParts = objectMapper.readValue(jsonStr, new TypeReference<ArrayList<Part>>() {});
} catch (Exception e) {
//fail("failed.");
e.printStackTrace();
}
//TODO: Assert: compare both list values.
}
I am also having the same problem. I have a json which is to be converted to ArrayList.
Account looks like this.
Account{
Person p ;
Related r ;
}
Person{
String Name ;
Address a ;
}
All of the above classes have been annotated properly.
I have tried TypeReference>() {}
but is not working.
It gives me Arraylist but ArrayList has a linkedHashMap which contains some more linked hashmaps containing final values.
My code is as Follows:
public T unmarshal(String responseXML,String c)
{
ObjectMapper mapper = new ObjectMapper();
AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();
mapper.getDeserializationConfig().withAnnotationIntrospector(introspector);
mapper.getSerializationConfig().withAnnotationIntrospector(introspector);
try
{
this.targetclass = (T) mapper.readValue(responseXML, new TypeReference<ArrayList<T>>() {});
}
catch (JsonParseException e)
{
e.printStackTrace();
}
catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return this.targetclass;
}
I finally solved the problem. I am able to convert the List in Json String directly to ArrayList as follows:
JsonMarshallerUnmarshaller<T>{
T targetClass ;
public ArrayList<T> unmarshal(String jsonString)
{
ObjectMapper mapper = new ObjectMapper();
AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();
mapper.getDeserializationConfig().withAnnotationIntrospector(introspector);
mapper.getSerializationConfig().withAnnotationIntrospector(introspector);
JavaType type = mapper.getTypeFactory().
constructCollectionType(ArrayList.class, targetclass.getClass()) ;
try
{
Class c1 = this.targetclass.getClass() ;
Class c2 = this.targetclass1.getClass() ;
ArrayList<T> temp = (ArrayList<T>) mapper.readValue(jsonString, type);
return temp ;
}
catch (JsonParseException e)
{
e.printStackTrace();
}
catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null ;
}
}
Related
private void extracted(Principal principal, UnoBorrowerStaging unoBorrowerStaging, Integer status, String remarks,
UnoBorrowerStagingRepo unoBorrowerStagingRepo, UnoBorrowerDetails unoBorrowerDetails) {
ObjectMapper objectMapper = new ObjectMapper();
String unoBorrowerDetailsAsString = null;
try {
unoBorrowerDetailsAsString = objectMapper.writeValueAsString(unoBorrowerDetails);
} catch (JsonProcessingException e1) {
e1.printStackTrace();
}
unoBorrowerStaging.setIs_processed(status);
unoBorrowerStaging.setRemarks(remarks);
unoBorrowerStaging.setPayload(unoBorrowerDetailsAsString);
unoBorrowerStaging.setCreatedBy(principal.getName());
unoBorrowerStagingRepo.save(unoBorrowerStaging);
}
private void extracted2(Principal principal, UnoDocumentsStaging unoDocumentsStaging, Integer status,
String remarks, UnoDocumentsStagingRepo unoDocumentsStagingRepo, UnoDocumentsEntity unoDocumentsEntity) {
ObjectMapper objectMapper = new ObjectMapper();
String jsonString = null;
try {
jsonString = objectMapper.writeValueAsString(unoDocumentsEntity);
} catch (JsonProcessingException e1) {
e1.printStackTrace();
}
unoDocumentsStaging.setIs_processed(status);
unoDocumentsStaging.setRemarks(remarks);
unoDocumentsStaging.setPayload(jsonString);
unoDocumentsStaging.setCreatedBy(principal.getName());
unoDocumentsStagingRepo.save(unoDocumentsStaging);
}
These two method bodies are the same, but the arguments are different like the entity class. I want to create one generic method where I pass the object and create instance of those passing parameters, in that way I don't have to create separate methods.
The above code is for parsing JSON into string then insert al the details into a database.
You can just use type Object instead of UnoDocumentsEntity and UnoBorrowerDetails.
Look at the signature of the method ObjectMapper#writeValueAsString(Object value)
https://fasterxml.github.io/jackson-databind/javadoc/2.7/com/fasterxml/jackson/databind/ObjectMapper.html#writeValueAsString(java.lang.Object)
I am facing issue in converting the nested list object to JSON.I am using object mapper and it is only converting the starting values and after that there is one arraylist inside it and it is not going through that list.
I have tried some basic iteration using JsonNode root = mapper.valueToTree(obj)so that i can iterate through the inner arraylist but i am not getting the result.I am new to this parsing conversion.
code snippet--
public class JsonUtils {
public static <T> String toJsonString(final T obj) throws IOException {
final ObjectMapper mapper = new ObjectMapper();
String jsonString = null;
try {
//JsonNode root = mapper.valueToTree(obj);
jsonString = mapper.writeValueAsString(obj);
} catch (final JsonProcessingException e) {
throw e;
} catch (IOException e) {
throw e;
}
return jsonString;
}
public static <T> String toJsonString(final List<T> lstObject) throws JSONException, IOException {
final JSONArray jsonArray = new JSONArray();
for (final T object : lstObject) {
final String json = JsonUtils.toJsonString(object);
final JSONObject jsonObj = new JSONObject(json);
jsonArray.put(jsonObj);
}
return jsonArray.toString();
}
}
So here is the result which i am getting -
[2, [{"geoMarketId":1,"geoname":"AP","geoId":1,"checked":false},
{"geoMarketId":7,"geoname":"EP","geoId":2,"checked":false},
{"geoMarketId":16,"geoname":"Japan","geoId":3,"checked":true},
{"geoMarketId":18,"geoname":"LA","geoId":4,"checked":true},
{"geoMarketId":22,"geoname":"MEA","geoId":5,"checked":true},
{"geoMarketId":24,"geoname":"NA","geoId":6,"checked":false}]]
Actual Result which should come-
{"geoMarketId":1,"geoname":"AP","geoId":1,"checked":false,
marketName:{"marketname":JP,"marketname":"AP","marketname":MP}}
My json conversion is ignoring this inner list in the same index.
Is there any way my json class can iterate and also convert that innerlist to JSON?
Based on this question How to get a class instance of generics type T I have implemented the following class:
public class OkJsonConverter<T> {
final Class<T> typeParameterClass;
public OkJsonConverter(Class<T> typeParameterClass) {
this.typeParameterClass = typeParameterClass;
}
protected T processJson(String json) throws OkClientException {
T object = null;
ObjectMapper objectMapper = new ObjectMapper();
try {
JsonNode jsonNode = objectMapper.readTree(json);
if (jsonNode.get("error_code") != null) {
Error error = objectMapper.treeToValue(jsonNode, Error.class);
throw new OkClientException("API returned error", error);
} else {
object = objectMapper.treeToValue(jsonNode, typeParameterClass);
}
} catch (IOException e) {
throw new OkClientException("unable to process json", e);
}
return object;
}
}
I can use this class with a generic parameters, for example:
return new OkJsonConverter<User>(User.class).processJson(response.getBody());
but right now I'm struggling how to make it working with a nested generic parameter like this one List<Method>
This code doesn't work:
return new OkJsonConverter<List<Method>>(List<Method>.class).processJson(response.getBody());
Please help to change this code in order to get it working.
Java doesn't have any way to represent that type as a Class. The closest approximation you can get is (Class<List<Method>>) (Class) List.class, but that cast just papers over that you're just looking at a basic List that doesn't know its element type.
Whether or not that works with your JSON converter isn't clear, but should be specified in the documentation of the converter you're using, which will have to deal with this itself, since this is a universal problem in Java when you're trying to reflect on generic types.
Finally, thanks to user3707125 I have found a way how to implement this:
Corrected by idierL
public class OkJsonConverter {
private static final String ERROR_CODE_FIELD_NAME = "error_code";
protected <T> T readTreeToValue(String json, TypeReference<T> valueTypeRef) throws OkClientException {
T object = null;
ObjectMapper objectMapper = new ObjectMapper();
try {
JsonNode jsonNode = objectMapper.readTree(json);
if (jsonNode.has(ERROR_CODE_FIELD_NAME)) {
Error error = objectMapper.treeToValue(jsonNode, Error.class);
throw new OkClientException("Ok API returned error", error);
} else {
JavaType type = objectMapper.getTypeFactory().constructType(valueTypeRef);
object = objectMapper.convertValue(jsonNode, type);
}
} catch (IOException e) {
throw new OkClientException("Unable to process JSON", e);
}
return object;
}
}
Now, the following code works fine:
List<Method> result = new OkJsonConverter().readTreeToValue(response.getBody(), new TypeReference<List<Method>>() {});
str = "[tdr1w6v, tdr1w77]";
ObjectMapper objectMapper = new ObjectMapper();
JavaType type = objectMapper.getTypeFactory().
constructCollectionType(ArrayList.class, String.class);
ArrayList<String> list = null;
try {
list = objectMapper.readValue(str,
new TypeReference<ArrayList<String>>(){});
} catch (IOException e) {
e.printStackTrace();
}
Here an exception is thrown :
com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'tdr1w6v': was expecting 'null', 'true', 'false' or NaN
How can I convert str to ArrayList of string ?
#FedericoPeraltaSchaffner suggestion helped. Now what I do is, in my binder class use objectMapper.writeValueAsString to convert data to store in database. And in my Mapper class while reading from data base I can use the same way as in the question:
ObjectMapper objectMapper = new ObjectMapper();
ArrayList<String> list = null;
try {
list =objectMapper.readValue(str, new TypeReference<ArrayList<String>>(){});
} catch (IOException e) {
e.printStackTrace();
}
So now I don't have to create a separate DTO class, I can use the same model at service layer and DAO.
The requirement can be easily met without using TypeReference
String str="[tdr1w6v, tdr1w77]";
List<String> al=Arrays.asList(str.replaceAll("[\\[\\]]","").split(","));
System.out.println(al);
Hi guys I have problem in Java. The problem is around parsing JSON with Jackson as I was instructed. My JSON is parsed well, that's not the problem. The problem lies in that I have multiple JSON items in one JSON. I've parsed it like this:
ObjectMapper objectMapper = new ObjectMapper();
try {
List<Unit> unitList = objectMapper.readValue(json,List.class);
System.out.println("UnitSize " + String.valueOf(unitList.size()));
System.out.println(unitList.get(0).getUnitEmail());
} catch (IOException e) {
e.printStackTrace();
}
and at UnitSize it'll tell me that I have precisely 5 objects of Unit type, which is okay, but when I want to get something out of the List it says me this:
Exception in thread "main" java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.reddatura.API.HTTPRequest$Unit
I've googled it, but nothing relevant. What should be the problem
EDIT:
here is my class snippet:
#JsonIgnoreProperties(ignoreUnknown = true)
public class Unit
{
#JsonProperty("unitid")
int unitId;
#JsonProperty("unitname")
String unitName;
#JsonProperty("unitlogo")
String unitLogo;
#JsonProperty("unitaddress")
String unitAddr;
//other fields, getters setters
#JsonCreator
public Unit()
{
}
}
I want to parse into this model
I think you are not casting correctly your json value:
Using jackson you could do the following:
List<Unit> myUnits = objectMapper.readValue(json, objectMapper.getTypeFactory().
constructCollectionType(List.class, Unit.class));
Hope it helps :)
try this
ObjectMapper objectMapper = new ObjectMapper();
try {
Unit[] unit = objectMapper.readValue(jsonString, Unit[].class);
Log.i("TEST", String.valueOf(unit.length)+" ******* "+unit[1].getUnitEmail()+" ******* "+unit[1].getUnitName());
// or
List<Unit> unit1 = objectMapper.readValue(jsonString, new TypeReference<List<Unit>>() { });
Log.i("TEST_1", String.valueOf(unit1.size())+" ****11111*** "+unit1.get(1).getUnitEmail()+" **1111111**** "+unit1.get(1).getUnitName());
} catch (IOException e) {
e.printStackTrace();
}
do something like this :
JSONObject jObject = new JSONObject(jsonString);
JSONArray jsonArray = jObject.getJSONArray("posts");
for (int i = 0; i < jsonArray.length(); i++) {
int a = jsonArray.getJSONObject(i).getInt("a"),
String s = jsonArray.getJSONObject(i).getString("b"));
}
jsonString is String variable and must be Json syntax