Deserialize JSON object from MongoDB to Java object on GET request - java

I have some nested classes in Java, simplified here. Getters and setters exist.
Example
public class Planet {
#JsonProperty("name")
private String name;
#JsonProperty("moons")
private List<Moon> moons;
}
public class Moon {
#JsonProperty("moonname")
private String name;
#JsonProperty("craters")
private int craters;
}
I want to be able to deserialize the records on mongo (following this same structure) to java objects on the rest controller, specifically the HTTP GET request.
#RestController
#RequestMapping("/planets")
public class PlanetController {
#Autowired
private PlanetService planetService;
#RequestMapping("/")
public List<Planet> getAllPlanets() {
//Need to deserialize here
return planetService.getAll();
}
#RequestMapping("/{name}")
public Planet getItemsWithName(#PathVariable("name") String name) {
//deserialize here
return planetService.getEntryWithName(name.toLowerCase());
}
PlanetService.getAll() is expecting return type of List. getEntryWithName() is expecting return type of Planet.
How can I loop the results in the getAll() so I can deserialize them before they are returned?
Using Jackson's object mapper, I can do the serialization of a Java object to a JSON object.
ObjectMapper mapper = new ObjectMapper();
try {
mapper.writeValue(new File("target/mars.json"), mars);
} catch (IOException e) {
e.printStackTrace();
}
I can probably use readValue for the opposite process but I don't know how to loop the results.
I will appreciate the help. Let me know if something is not clear.

public List<Planet> getAllPlanets() {
List<Planet> planets = planetService.getAll();
String jsonString = new ObjectMapper().writeValueAsString(planets);
return planets;
}

Related

Android DynamoDBMappingException: Expected S in value

I'm trying to map a json object from my dynamodb table using DynamoDbMapper and with the latest aws android sdk: com.amazonaws:aws-android-sdk-ddb-mapper:2.13.0, I'm seeing this exception: "DynamoDBMappingException: Expected S in value...
The json object in my table has 3 attributes, 2 of which are string and the third is a list of complex objects. I've created an object using the #DynamoDbDocument annotation for the complex object and used the proper marshaling annotation but it doesn't seem to be unmarshaling the json object into a java object correctly.
The complex object is a json object in this format:
{
"allCitiesList": [
{
"city": "Auckland, New Zealand",
"times": {
"recTimes": [
"Jan1",
"Jan2"
]
}
}
}
public class CitiesDO {
private String city;
private String country;
private List<AllCitiesObject> allCitiesList;
...get/setters for other fields...
#DynamoDBMarshalling(marshallerClass =
AllCitiesJSONMarshaller.class)
public List<AllCitiesObject> getAllCitiesList() {
return allCitiesList;
}
public void setAllCitiesList(List<AllCitiesObject> allCitiesList) {
this.allCitiesList = allCitiesList;
}
}
#DynamoDBDocument
public class AllCitiesObject {
#DynamoDBAttribute(attributeName = "allCitiesList")
private String data;
public AllCitiesObject(){}
public String getData() {
return data.toString();
}
public void setData(String data) {
this.data = data;
}
}
class AllCitiesJSONMarshaller extends JsonMarshaller<AllCitiesObject> {}
Have also tried this approach with a custom marshaller but no success:
public class MyCustomMarshaller implements DynamoDBMarshaller<List<AllCitiesObject>> {
private static final ObjectMapper mapper = new ObjectMapper();
private static final ObjectWriter writer = mapper.writer();
#Override
public String marshall(List<AllCitiesObject> obj) {
try {
return writer.writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new RuntimeException(
"Unable to marshall the instance of " + obj.getClass()
+ "into a string", e);
}
}
#Override
public List<AllCitiesObject> unmarshall(Class<List<AllCitiesObject>> clazz, String json) {
final CollectionType
type =
mapper.getTypeFactory().constructCollectionType(List.class, AllCitiesObject.class);
try {
return mapper.readValue(json, type);
} catch (Exception e) {
throw new RuntimeException("Unable to unmarshall the string " + json
+ "into " + clazz, e);
}
}
}
The exception is:
DynamoDBMappingException: Expected S in value {L: [{M: {times={M: {recTimes={L: [{S: Jan1,}, {S: Jan2,}
I'm having difficulty unmarshalling the json to a string although I think I have it set up correctly. Can anyone please help me understand what I'm missing and how to approach this issue? I would really appreciate your help!
DynamoDBMarshalling is deprecated, so I suggest using the newer DynamoDBTypeConverted annotation.
There are some useful notes on Mapping Arbitrary Data.
You can also see an example of mine in this answer
In summary, you create an AllCities plain java object. You then write a simple converter class which tells DynamoDB how to turn your AllCities object into a string to get into DynamoDB. Similarly, the converter class tells your application how to turn the string back into a Java object.
If anyone else is absolutely stuck on this issue with the ddbMapper, consider using the ddbClient to explicitly convert and map your DO object with your ddb table data. Due to time constraints, I'll come back to this and figure out the mapping issue at a later time and post the answer here in case it helps anyone else.

serialize json array into java objects

I have a JSON array like as shown below which I need to serialize it to my class. I am using Jackson in my project.
[
{
"clientId": "111",
"clientName": "mask",
"clientKey": "abc1",
"clientValue": {}
},
{
"clientId": "111",
"clientName": "mask",
"clientKey": "abc2",
"clientValue": {}
}
]
In above JSON array, clientValue will have another JSON object in it. How can I serialize my above JSON array into my java class using Jackson?
public class DataRequest {
#JsonProperty("clientId")
private String clientId;
#JsonProperty("clientName")
private int clientName;
#JsonProperty("clientKey")
private String clientKey;
#JsonProperty("clientValue")
private Map<String, Object> clientValue;
//getters and setters
}
I have not used jackson before so I am not sure how can I use it to serialize my JSON array into Java objects? I am using jackson annotation here to serialize stuff but not sure what will be my next step?
You can create a utility function shown below. You may want to change the Deserialization feature based on your business needs. In my case, I did not want to fail on unknown properties => (FAIL_ON_UNKNOWN_PROPERTIES, false)
static <T> T mapJson(String body,
com.fasterxml.jackson.core.type.TypeReference<T> reference) {
T model = null;
if(body == null) {
return model;
}
com.fasterxml.jackson.databind.ObjectMapper mapper =
new com.fasterxml.jackson.databind.ObjectMapper();
mapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
false);
try {
model = mapper.readValue(body, reference);
} catch (IOException e) {
//TODO: log error and handle accordingly
}
return model;
}
You can call it using similar approach as shown below:
mapJson(clientValueJsonString,
new com.fasterxml.jackson.core.type.TypeReference<List<DataRequest>>(){});
You can try #JsonAnyGetter and #JsonAnySetter annotations with an inner class object. Also clientName should have type String, not int.
public class DataRequest {
private String clientId;
private String clientName;
private String clientKey;
private ClientValue clientValue;
//getters and setters
}
public class ClientValue {
private Map<String, String> properties;
#JsonAnySetter
public void add(String key, String value) {
properties.put(key, value);
}
#JsonAnyGetter
public Map<String,String> getProperties() {
return properties;
}
}

Json Data assign to java class

I'm having problem to assign json data into java class.Please do help anyone,
My java class is like,
public class ListofGridRecords<T> {
public int Totalrecords;
public List<T> GridRecords;//using TraderTransaction class.
}
and TraderTransaction class is,
public class TraderTransaction {
public Date AddedTime;
public String TransactId;
public TransactStatus Status;
public String OtherPartyAccountNo;
public Double AmountPaid;
public Double AmountRecieved;
public Double ClosingBalance;
public TransactionTypes TransType;
public String Narration;
public TraderTransaction() {
super();
}
}
and my json conversion function look like,
JsonObject returndata = JsonObject.parse(responseString);
String operationresult = returndata.get("OperationResult").toString();
if (Result.values()[Integer.parseInt(operationresult)] == Result.Success) {
Gson gson = new Gson();
#SuppressWarnings("unchecked")
ListofGridRecords<TraderTransaction> traderlist =
gson.fromJson(returndata.get("ResultData").toString(), ListofGridRecords.class);
Log.i("LIST DATA:", "" + traderlist);
for (TraderTransaction trader: traderlist.GridRecords) {
HashMap<String, String> map = new HashMap<String, String>();
map.put(TRANS_FIRST_COLUMN, currentformatter.format(trader.AddedTime));
map.put(TRANS_SECOND_COLUMN, trader.TransactId);
map.put(TRANS_THIRD_COLUMN, trader.OtherPartyAccountNo);
map.put(TRANS_FOURTH_COLUMN, trader.AmountPaid.toString());
map.put(TRANS_FIFTH_COLUMN, trader.AmountRecieved.toString());
map.put(TRANS_SIXTH_COLUMN, OpenOrClosed.values()[Integer.parseInt(trader.TransType.toString())].toString());
list.add(map);
}
}
I'm getting conversion error at for (TraderTransaction trader : traderlist.GridRecords).
My Json data look like,
{
"Messages":"RESULTS_RETRIEVAL_SUCCESSFULL",
"OperationResult":0,
"ResultData":{
"GridRecords":[
{
"AddedBy":"Distributor-9787457361-Rathinavel",
"AddedTime":"2013-04-12T16:26:24.0140117",
"AmountPaid":0.0,
"AmountRecieved":10000.0,
"ClosingBalance":10000.0,
"Narration":null,
"OtherPartyAccountNo":"0102849015327675",
"Status":2,
"TransType":2,
"TransactId":"TDRF483679051236"
},
{
"AddedBy":"Distributor-9787457361-Rathinavel",
"AddedTime":"2013-04-12T16:20:54.8681857",
"AmountPaid":0.0,
"AmountRecieved":0.0,
"ClosingBalance":0.0,
"Narration":null,
"OtherPartyAccountNo":"0102849015327675",
"Status":0,
"TransType":2,
"TransactId":"TDRF706925413802"
}
],
"Totalrecords":2
},
"UpdateAvailable":"0"
}
In order to parse your JSON, I'd use a slightly different strategy. As you seem to be interested in parsing only the "ResultData", I'd create classes to wrap the response, very similar to those you have already created, namely:
public class Response {
#SerializedName("ResultData")
public ResultData resultData;
}
and,
public class ResultData {
#SerializedName("GridRecords")
public List<GridRecord> gridRecords;
#SerializedName("Totalrecords")
public int totalrecords;
}
and,
public class GridRecord {
#SerializedName("AddedTime")
public String addedTime;
#SerializedName("TransactId")
public String transactId;
//other fields...
}
and other classes if necessary...
Then, in order to parse your JSON reponse, you just have to do:
Gson gson = new Gson();
Response data = gson.fromJson(responseString, Response.class);
and you'll be able to access any field, for example:
data.resultData.gridRecords.transactId;
Note 1: If you are interested in more fields of the JSON response, you just have to add more fields to your wrap classes, according to the JSON response...
Note 2: I've changed the type of addedTime to String, instead of Date because it throws an exception for unparseable date. Anyway I usually leave the types in the Response objects as simple String and then in the class from where I retrieve the response, I do the correct formatting while creating my objects, for example, when you put the values in your Map...
Note 3: The use of the annotation #SerializedName is interesting to separate the name of a field in the JSON response and in your app, in order to follow Java naming conventions, which your attributes are not following...
Note 4: You shouldn't use public attributes in your classes. It's more recommendable to use private/protected attributes and their correspondent getters and setters...

Custom Xstream/JSON converter for enum

I have the following Enum:
public enum MyState {
Open("opened"),
Close("closed"),
Indeterminate("unknown");
private String desc;
private MyState(String desc) {
setDesc(desc);
}
public String getDesc() {
return this.desc;
}
private void setDesc(String desc) {
this.desc = desc;
}
}
I am trying to write an XStream Converter that will know to map back a JSON element "mystate" to a MyState instance.
"someJson": {
"object1": {
"mystate": closed
}
}
This should produce, amongst other objects (someJson and object1) a MyState.Close instance. I've started the Converter, but haven't gotten very far:
public class MyStateEnumConverter implement Converter {
#Override
public boolean canConvert(Class clazz) {
return clazz.equals(MyState.class);
}
#Override
public void marshal(Object value, HierarchialStreamWriter writer, MarshallingContext context) {
??? - no clue here
}
#Override
public Object unmarshal(HierarchialStreamReader reader, UnmarshallingContext context) {
??? - no clue here
}
}
Then, to create the mapper and use it:
XStream mapper = new XStream(new JettisonMappedXmlDriver());
mapper.registerConverter(new MyStateEnumConverter);
SomeJson jsonObj = mapper.fromXML(jsonString);
// Should print "closed"
System.out.println(jsonObject.getObject1().getMyState().getDesc());
How can I implement marshal and unmarshal so thatI get the desired mapping? Thanks in advance!
You can accomplish this by doing 2 things:
Adding a lookup method as well as a toString() override to your enum (MyStateEnum); and
Extending XStream's AbstractSingleValueConverter instead of implementing Converter
MyStateEnum:
public enum MyStateEnum {
// Everything you had is fine
// But now, add:
public static MyStateEnum getMyStateByDesc(String desc) {
for(MyStateEnum myState : MyStateEnum.values())
if(myState.getDesc().equals(desc))
return myState;
return null;
}
#Override
public String toString() {
return getDesc();
}
}
MyStateEnumConverter:
public class MyStateEnumConverter extends AbstractSingleValueConverter {
#Override
public boolean canConvert(Class clazz) {
return clazz.equals(MyStateEnum.class);
}
#Override
public Object fromString(String parsedText) {
return MyStateEnum.getMyStateByDesc(parsedText);
}
}
By adding getMyStateByDesc(String) to your enum, you now have a way to look up all the various enumerated values from the outside, by providing a desc string. The MyStateEnumConverter (which extends AbstractSingleValueConverter) uses your toString() override under the hood to associate aMyStateEnum instance with a text string.
So when XStream is parsing the JSON, it sees a JSON object of, say, "opened", and this new converter knows to pass "opened" into the converter's fromString(String) method, which in turn uses getMyStateByDesc(String) to lookup the appropriate enum instance.
Don't forget to register your converter with your XStream instance as you already showed in your original question.
You can use the EnumToStringConverter
Documentation
Example
#XStreamConverter(EnumToStringConverter.class)
public enum MyStateEnum {
enter code here
...
Use xstream.autodetectAnnotations(true)
Why are you using xstream for json support? You have a couple of other libraries specialized in json and that do it well. Also closed without quotes is not valid json.
Try for example Genson, it will work out of the box.
The values in the json stream would be "Close", "Indeterminate", etc and when deserializing it will produce the correct enum.
class SomeObject {
private MyState state;
...
}
Genson genson = new Genson();
// json = {"state" : "Indeterminate"}
String json = genson.serialize(new SomeObject(MyState.Indeterminate));
// deserialize back
SomeObject someObject = genson.deserialize(json, SomeObject.class);
// will print unknown
System.out.println(someObject.getDesc());

How can I include raw JSON in an object using Jackson?

I am trying to include raw JSON inside a Java object when the object is (de)serialized using Jackson. In order to test this functionality, I wrote the following test:
public static class Pojo {
public String foo;
#JsonRawValue
public String bar;
}
#Test
public void test() throws JsonGenerationException, JsonMappingException, IOException {
String foo = "one";
String bar = "{\"A\":false}";
Pojo pojo = new Pojo();
pojo.foo = foo;
pojo.bar = bar;
String json = "{\"foo\":\"" + foo + "\",\"bar\":" + bar + "}";
ObjectMapper objectMapper = new ObjectMapper();
String output = objectMapper.writeValueAsString(pojo);
System.out.println(output);
assertEquals(json, output);
Pojo deserialized = objectMapper.readValue(output, Pojo.class);
assertEquals(foo, deserialized.foo);
assertEquals(bar, deserialized.bar);
}
The code outputs the following line:
{"foo":"one","bar":{"A":false}}
The JSON is exactly how I want things to look. Unfortunately, the code fails with an exception when attempting to read the JSON back in to the object. Here is the exception:
org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: java.io.StringReader#d70d7a; line: 1, column: 13] (through reference chain: com.tnal.prism.cobalt.gather.testing.Pojo["bar"])
Why does Jackson function just fine in one direction but fail when going the other direction? It seems like it should be able to take its own output as input again. I know what I'm trying to do is unorthodox (the general advice is to create an inner object for bar that has a property named A), but I don't want to interact with this JSON at all. My code is acting as a pass-through for this code -- I want to take in this JSON and send it back out again without touching a thing, because when the JSON changes I don't want my code to need modifications.
Thanks for the advice.
EDIT: Made Pojo a static class, which was causing a different error.
#JsonRawValue is intended for serialization-side only, since the reverse direction is a bit trickier to handle. In effect it was added to allow injecting pre-encoded content.
I guess it would be possible to add support for reverse, although that would be quite awkward: content will have to be parsed, and then re-written back to "raw" form, which may or may not be the same (since character quoting may differ).
This for general case. But perhaps it would make sense for some subset of problems.
But I think a work-around for your specific case would be to specify type as 'java.lang.Object', since this should work ok: for serialization, String will be output as is, and for deserialization, it will be deserialized as a Map. Actually you might want to have separate getter/setter if so; getter would return String for serialization (and needs #JsonRawValue); and setter would take either Map or Object. You could re-encode it to a String if that makes sense.
Following #StaxMan answer, I've made the following works like a charm:
public class Pojo {
Object json;
#JsonRawValue
public String getJson() {
// default raw value: null or "[]"
return json == null ? null : json.toString();
}
public void setJson(JsonNode node) {
this.json = node;
}
}
And, to be faithful to the initial question, here is the working test:
public class PojoTest {
ObjectMapper mapper = new ObjectMapper();
#Test
public void test() throws IOException {
Pojo pojo = new Pojo("{\"foo\":18}");
String output = mapper.writeValueAsString(pojo);
assertThat(output).isEqualTo("{\"json\":{\"foo\":18}}");
Pojo deserialized = mapper.readValue(output, Pojo.class);
assertThat(deserialized.json.toString()).isEqualTo("{\"foo\":18}");
// deserialized.json == {"foo":18}
}
}
I was able to do this with a custom deserializer (cut and pasted from here)
package etc;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
/**
* Keeps json value as json, does not try to deserialize it
* #author roytruelove
*
*/
public class KeepAsJsonDeserializer extends JsonDeserializer<String> {
#Override
public String deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException {
TreeNode tree = jp.getCodec().readTree(jp);
return tree.toString();
}
}
Use it by annotating the desired member like this:
#JsonDeserialize(using = KeepAsJsonDeserializer.class)
private String value;
#JsonSetter may help. See my sample ('data' is supposed to contain unparsed JSON):
class Purchase
{
String data;
#JsonProperty("signature")
String signature;
#JsonSetter("data")
void setData(JsonNode data)
{
this.data = data.toString();
}
}
This is a problem with your inner classes. The Pojo class is a non-static inner class of your test class, and Jackson cannot instantiate that class. So it can serialize, but not deserialize.
Redefine your class like this:
public static class Pojo {
public String foo;
#JsonRawValue
public String bar;
}
Note the addition of static
Adding to Roy Truelove's great answer, this is how to inject the custom deserialiser in response to appearance of #JsonRawValue:
import com.fasterxml.jackson.databind.Module;
#Component
public class ModuleImpl extends Module {
#Override
public void setupModule(SetupContext context) {
context.addBeanDeserializerModifier(new BeanDeserializerModifierImpl());
}
}
import java.util.Iterator;
import com.fasterxml.jackson.annotation.JsonRawValue;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.deser.BeanDeserializerBuilder;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
public class BeanDeserializerModifierImpl extends BeanDeserializerModifier {
#Override
public BeanDeserializerBuilder updateBuilder(DeserializationConfig config, BeanDescription beanDesc, BeanDeserializerBuilder builder) {
Iterator<SettableBeanProperty> it = builder.getProperties();
while (it.hasNext()) {
SettableBeanProperty p = it.next();
if (p.getAnnotation(JsonRawValue.class) != null) {
builder.addOrReplaceProperty(p.withValueDeserializer(KeepAsJsonDeserialzier.INSTANCE), true);
}
}
return builder;
}
}
This easy solution worked for me:
public class MyObject {
private Object rawJsonValue;
public Object getRawJsonValue() {
return rawJsonValue;
}
public void setRawJsonValue(Object rawJsonValue) {
this.rawJsonValue = rawJsonValue;
}
}
So I was able to store raw value of JSON in rawJsonValue variable and then it was no problem to deserialize it (as object) with other fields back to JSON and send via my REST. Using #JsonRawValue didnt helped me because stored JSON was deserialized as String, not as object, and that was not what I wanted.
This even works in a JPA entity:
private String json;
#JsonRawValue
public String getJson() {
return json;
}
public void setJson(final String json) {
this.json = json;
}
#JsonProperty(value = "json")
public void setJsonRaw(JsonNode jsonNode) {
// this leads to non-standard json, see discussion:
// setJson(jsonNode.toString());
StringWriter stringWriter = new StringWriter();
ObjectMapper objectMapper = new ObjectMapper();
JsonGenerator generator =
new JsonFactory(objectMapper).createGenerator(stringWriter);
generator.writeTree(n);
setJson(stringWriter.toString());
}
Ideally the ObjectMapper and even JsonFactory are from the context and are configured so as to handle your JSON correctly (standard or with non-standard values like 'Infinity' floats for example).
Here is a full working example of how to use Jackson modules to make #JsonRawValue work both ways (serialization and deserialization):
public class JsonRawValueDeserializerModule extends SimpleModule {
public JsonRawValueDeserializerModule() {
setDeserializerModifier(new JsonRawValueDeserializerModifier());
}
private static class JsonRawValueDeserializerModifier extends BeanDeserializerModifier {
#Override
public BeanDeserializerBuilder updateBuilder(DeserializationConfig config, BeanDescription beanDesc, BeanDeserializerBuilder builder) {
builder.getProperties().forEachRemaining(property -> {
if (property.getAnnotation(JsonRawValue.class) != null) {
builder.addOrReplaceProperty(property.withValueDeserializer(JsonRawValueDeserializer.INSTANCE), true);
}
});
return builder;
}
}
private static class JsonRawValueDeserializer extends JsonDeserializer<String> {
private static final JsonDeserializer<String> INSTANCE = new JsonRawValueDeserializer();
#Override
public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
return p.readValueAsTree().toString();
}
}
}
Then you can register the module after creating the ObjectMapper:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JsonRawValueDeserializerModule());
String json = "{\"foo\":\"one\",\"bar\":{\"A\":false}}";
Pojo deserialized = objectMapper.readValue(json, Pojo.class);
I had the exact same issue.
I found the solution in this post :
Parse JSON tree to plain class using Jackson or its alternatives
Check out the last answer.
By defining a custom setter for the property that takes a JsonNode as parameter and calls the toString method on the jsonNode to set the String property, it all works out.
Using an object works fine both ways... This method has a bit of overhead deserializing the raw value in two times.
ObjectMapper mapper = new ObjectMapper();
RawJsonValue value = new RawJsonValue();
value.setRawValue(new RawHello(){{this.data = "universe...";}});
String json = mapper.writeValueAsString(value);
System.out.println(json);
RawJsonValue result = mapper.readValue(json, RawJsonValue.class);
json = mapper.writeValueAsString(result.getRawValue());
System.out.println(json);
RawHello hello = mapper.readValue(json, RawHello.class);
System.out.println(hello.data);
RawHello.java
public class RawHello {
public String data;
}
RawJsonValue.java
public class RawJsonValue {
private Object rawValue;
public Object getRawValue() {
return rawValue;
}
public void setRawValue(Object value) {
this.rawValue = value;
}
}
I had a similar problem, but using a list with a lot of JSON itens (List<String>).
public class Errors {
private Integer status;
private List<String> jsons;
}
I managed the serialization using the #JsonRawValue annotation. But for deserialization I had to create a custom deserializer based on Roy's suggestion.
public class Errors {
private Integer status;
#JsonRawValue
#JsonDeserialize(using = JsonListPassThroughDeserialzier.class)
private List<String> jsons;
}
Below you can see my "List" deserializer.
public class JsonListPassThroughDeserializer extends JsonDeserializer<List<String>> {
#Override
public List<String> deserialize(JsonParser jp, DeserializationContext cxt) throws IOException, JsonProcessingException {
if (jp.getCurrentToken() == JsonToken.START_ARRAY) {
final List<String> list = new ArrayList<>();
while (jp.nextToken() != JsonToken.END_ARRAY) {
list.add(jp.getCodec().readTree(jp).toString());
}
return list;
}
throw cxt.instantiationException(List.class, "Expected Json list");
}
}

Categories

Resources