I want to map the following json to a pojo in Java. In the snippet shown below, result is a Json object, whose value is another json object which is a map. I tried converting this to a Pojo, but it failed. The keys in the result map are dynamic, and I cannot guess them prior.
final_result :
{
"result":
{
"1597696140": 70.32,
"1597696141": 89.12,
"1597696150": 95.32,
}
}
The pojo that I created is :
#JsonIgnoreProperties(ignoreUnknown = true)
public class ResultData {
Map<Long, Double> resultMap;
public ResultData(Map<Long, Double> resultMap) {
this.resultMap = resultMap;
}
public ResultData() {
}
#Override
public String toString() {
return super.toString();
}
}
Upon trying to create the pojo using ObjectMapper :
ObjectMapper objectMapper = new ObjectMapper();
ResultData resultData = objectMapper.readValue(resultData.getJSONObject("result").toString(), ResultData.class);
What am I possible doing wrong here ?
Assume, your JSON payload looks like below:
{
"final_result": {
"result": {
"1597696140": 70.32,
"1597696141": 89.12,
"1597696150": 95.32
}
}
}
You can deserialise it to class:
#JsonRootName("final_result")
class ResultData {
private Map<Long, Double> result;
public Map<Long, Double> getResult() {
return result;
}
#Override
public String toString() {
return result.toString();
}
}
Like below:
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.io.IOException;
import java.util.Map;
public class Main {
public static void main(String[] args) throws IOException {
File jsonFile = new File("./src/main/resources/test.json");
ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
ResultData resultData = mapper.readValue(jsonFile, ResultData.class);
System.out.println(resultData);
}
}
Above code prints:
{1597696140=70.32, 1597696141=89.12, 1597696150=95.32}
Converting the JSONObject to Map and setting the map to the pojo field, solved the issue and didn't lead me to writing a custom deserializer.
Map<Long, Double> resultData = objectMapper.readValue(resultData.getJSONObject("result").toString(), Map.class);
FinalResultData finaResultData = new FinalResultData(resultData);
Related
Is it possible to have something like below while serializing a JSON in the same class
#JsonProperty("stats")
private StatsDetails statsDetails
#JsonProperty("stats")
private List<StatsDetails> statsDetailsList
so i can have either statsDetails or statsDetailsList only one of these being included while forming a json.
I also have a separate JsonMapper code that transforms this pojo data into a json which i haven't included here.
You cannot do that. It will throw JsonMappingException jackson cannot know which of the fields are you referring to. You can try it by yourself with the following code:
POJOClass:
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
import java.util.List;
public class POJOClass {
public POJOClass(String object) {
this.object = object;
}
public POJOClass(List<String> objectList) {
this.objectList = objectList;
}
#JsonProperty("object")
public String object;
#JsonProperty("object")
public List<String> objectList;
#JsonGetter("object")
public String getObject() {
return object;
}
#JsonGetter("object")
public List<String> getObjectList() {
return objectList;
}
#JsonSetter("object")
public void setObject(String object) {
this.object = object;
}
#JsonSetter("object")
public void setObjectList(List<String> objectList) {
this.objectList = objectList;
}
}
Main class:
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public class MainClass {
public static void main(String[] args) {
String text = "f";
List<String> list = Arrays.asList("a", "b", "c");
ObjectMapper mapper = new ObjectMapper();
try {
String json = mapper.writeValueAsString(new POJOClass(text));
String listJson = mapper.writeValueAsString(new POJOClass(list));
System.out.println("json=" + json);
System.out.println("listJson=" + listJson);
} catch (IOException e) {
e.printStackTrace();
}
}
}
The output:
com.fasterxml.jackson.databind.JsonMappingException: Multiple fields representing property "object": POJOClass#object vs POJOClass#objectList
{
"key1": {
"parameter1": "String1",
"parameter2": "String2"
},
"key2": {
"parameter1": "String3",
"parameter2": "String4"
},
"key3": {
"parameter1": "String5",
"parameter2": "String6"
}
}
I have the above JSON (/Users/user1/Desktop/responseMap.json) which is basically a Map<String, MockResponse> where MockResponse is the below POJO:
public class MockResponse {
public String parameter1;
public String parameter2;
}
Now, I have another POJO - TestCase, and another JSON - testCase.json as below:
public class TestCase {
public String responseMapFileLocation;
public String mockResponseKey;
public MockResponse mockResponse;
}
testCase.json
{
"responseMapFileLocation": "/Users/user1/Desktop/responseMap.json",
"mockResponseKey": "key1",
"mockResponse": null
}
What I am able to do is first map testCase.json to TestCase using Jackson, then map responseMap.json to Map<String, MockResponse>, then in my code search for mockResponseKey in the map.
But what I want to do is when I map testCase.json to TestCase using Jackson, I want the value of variable mockResponse to set automatically based on the value of variable mockResponseKey using the first JSON map.
You need to write custom deserialiser for TestCase class. In custom deserialiser you can parse basic properties: responseMapFileLocation, mockResponseKey and load mockResponse from other file. To deserialiser MockResponse you can use new ObjectMapper instance. Below code shows how this concept could be implemented:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.type.MapType;
import java.io.File;
import java.io.IOException;
import java.util.Map;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.readValue(jsonFile, TestCase.class));
}
}
class MockResponse {
public String parameter1;
public String parameter2;
}
#JsonDeserialize(using = TestCaseFromExternalFileDeserializer.class)
class TestCase {
public String responseMapFileLocation;
public String mockResponseKey;
public MockResponse mockResponse;
}
class TestCaseFromExternalFileDeserializer extends JsonDeserializer<TestCase> {
private final ObjectMapper mapper;
private final MapType mapType;
public TestCaseFromExternalFileDeserializer() {
mapper = new ObjectMapper();
mapType = mapper.getTypeFactory().constructMapType(Map.class, String.class, MockResponse.class);
}
#Override
public TestCase deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
TreeNode treeNode = p.readValueAsTree();
TestCase testCase = new TestCase();
testCase.responseMapFileLocation = ((JsonNode) treeNode.get("responseMapFileLocation")).asText();
testCase.mockResponseKey = ((JsonNode) treeNode.get("mockResponseKey")).asText();
parseMockResponse(testCase);
return testCase;
}
private void parseMockResponse(TestCase testCase) throws IOException {
Map<String, MockResponse> map = mapper.readValue(new File(testCase.responseMapFileLocation), mapType);
testCase.mockResponse = map.get(testCase.mockResponseKey);
}
}
You need to implement only toString method for each POJO class. Above code prints:
TestCase{responseMapFileLocation='./resource/responseMap.json', mockResponseKey='key1', mockResponse=MockResponse{parameter1='String1', parameter2='String2'}}
Both JSON files are in resource folder.
See also:
How use jackson ObjectMapper inside custom deserializer?
Jackson Streaming API - if you want to implement MockResponse deserialisation in faster way.
Tweaking the getter setter in your Test class and marking the field as private I was able to make it dynamic (Imports are from org.codehaus.jackson package)
class TestCase {
private String responseMapFileLocation;
private String mockResponseKey;
#JsonIgnore
private MockResponse mockResponse; //else value will be override in json value
public String getResponseMapFileLocation() {
return responseMapFileLocation;
}
public void setResponseMapFileLocation(String responseMapFileLocation) {
this.responseMapFileLocation = responseMapFileLocation;
}
public String getMockResponseKey() {
return mockResponseKey;
}
public void setMockResponseKey(String mockResponseKey1) throws IOException {
ObjectMapper mapper = new ObjectMapper();
Map<String, MockResponse> map = mapper.readValue(new File("C:\\Users\\Json1.json"), TypeFactory.mapType(HashMap.class, String.class, MockResponse.class));
this.mockResponse = map.get(mockResponseKey1);
this.mockResponseKey = mockResponseKey1;
}
public MockResponse getMockResponse() {
return mockResponse;
}
#Override
public String toString() {
return "TestCase [responseMapFileLocation=" + responseMapFileLocation + ", mockResponseKey=" + mockResponseKey
+ ", mockResponse=" + mockResponse + "]";
}
}
class MockResponse {
public String parameter1;
public String parameter2;
#Override
public String toString() {
return "MockResponse [parameter1=" + parameter1 + ", parameter2=" + parameter2 + "]";
}
}
and Running below code
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
TestCase testCase = mapper.readValue(new File("C:\\UsersJson2.json"), TestCase.class);
System.out.println(testCase);
}
output will be
TestCase [responseMapFileLocation=/Users/user1/Desktop/responseMap.json, mockResponseKey=key1, mockResponse=MockResponse [parameter1=String1, parameter2=String2]]
What you are asking for is not possible with just Jackson. Jackson is primarily a marshalling/unmarshalling tool, converting JSONs to Objects and vice versa. In other words, the value of the object must be known at the time of unmarshalling.
However you can unmarshal your json as a HashMap using the code:
new JSONObject(map);
search for the MockResponse-as-a-string using the mockResponseKey and then unmarshal that code into a new MockResponse.
I have a JSON string which looks like this:
{
"status": "status",
"date": "01/10/2019",
"alerts": {
"labels": {
"field1": "value1",
"field2": "value2",
"field3": "value3",
"field100": "value100"
},
"otherInfo" : "other stuff"
},
"description": "some description"
}
My corresponding Java classes look like the following:
public class Status {
private String status;
private String date;
private Alerts alerts;
private String description;
}
And
public class Alerts {
private Map<String, String> labels;
private String otherInfo;
public Map<String, String> getLabels() {
return labels();
}
}
I'm parsing the given JSON into Java object using this:
Status status = gson.fromJson(statusJSONString, Status.class);
This also gives me Alerts object from Status class:
Alerts alerts = status.getAlerts();
Here is my problem:
Let's consider the labels:
I want to make keys in the label map the case-insensitive. So for example, if the provided key/value pair is "field1" : "value1", or "Field1" : "value1" or "fIeLD1":"value1", I want to be able to retrieve them by simply calling alerts.getLabels.get("field1").
Ideally, I want to set the keys to be lowercase when the labels map is originally created. I looked into Gson deserialization examples, but I'm not clear exactly how to approach this.
There isnt really much you can do here. Even if you extended HashMap, the problem is that when the JSON is de-serialized, it doesn't call native methods. What you COULD do is the following, but it is rather cumbersome:
import java.util.HashMap;
public class HashMapCaseInsensitive extends HashMap<String, String> {
private boolean convertedToLower = false;
#Override
public String put(String key, String value) {
if(!convertedToLower){
convertToLower();
}
return super.put(key.toLowerCase(), value);
}
#Override
public String get(Object key) {
if(!convertedToLower){
convertToLower();
}
return super.get(key.toString().toLowerCase());
}
private void convertToLower(){
for(String key : this.keySet()){
String data = this.get(key);
this.remove(key);
this.put(key.toLowerCase(), data);
}
convertedToLower = true;
}
}
You can write your own MapTypeAdapterFactory which creates Map always with lowered keys. Our adapter will be based on com.google.gson.internal.bind.MapTypeAdapterFactory. We can not extend it because it is final but our Map is very simple so let's copy only important code:
class LowercaseMapTypeAdapterFactory implements TypeAdapterFactory {
#Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
TypeAdapter<String> stringAdapter = gson.getAdapter(TypeToken.get(String.class));
return new TypeAdapter<T>() {
#Override
public void write(JsonWriter out, T value) { }
#Override
public T read(JsonReader in) throws IOException {
JsonToken peek = in.peek();
if (peek == JsonToken.NULL) {
in.nextNull();
return null;
}
Map<String, String> map = new HashMap<>();
in.beginObject();
while (in.hasNext()) {
JsonReaderInternalAccess.INSTANCE.promoteNameToValue(in);
String key = stringAdapter.read(in).toLowerCase();
String value = stringAdapter.read(in);
String replaced = map.put(key, value);
if (replaced != null) {
throw new JsonSyntaxException("duplicate key: " + key);
}
}
in.endObject();
return (T) map;
}
};
}
}
Now, we need to inform that our Map should be deserialised with our adapter:
class Alerts {
#JsonAdapter(value = LowercaseMapTypeAdapterFactory.class)
private Map<String, String> labels;
private String otherInfo;
// getters, setters, toString
}
Assume that our JSON payload looks like below:
{
"status": "status",
"date": "01/10/2019",
"alerts": {
"labels": {
"Field1": "value1",
"fIEld2": "value2",
"fielD3": "value3",
"FIELD100": "value100"
},
"otherInfo": "other stuff"
},
"description": "some description"
}
Example usage:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.annotations.JsonAdapter;
import com.google.gson.internal.JsonReaderInternalAccess;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class GsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
Gson gson = new GsonBuilder().create();
Status status = gson.fromJson(new FileReader(jsonFile), Status.class);
System.out.println(status.getAlerts());
}
}
Above code prints:
Alerts{labels={field1=value1, field100=value100, field3=value3, field2=value2}, otherInfo='other stuff'}
This is really tricky solution and it should be used carefully. Do not use this adapter with much complex Map-es. From other side, OOP prefers much simple solutions. For example, create decorator for a Map like below:
class Labels {
private final Map<String, String> map;
public Labels(Map<String, String> map) {
Objects.requireNonNull(map);
this.map = new HashMap<>();
map.forEach((k, v) -> this.map.put(k.toLowerCase(), v));
}
public String getValue(String label) {
return this.map.get(label.toLowerCase());
}
// toString
}
Add new method to Alerts class:
public Map<String, String> toLabels() {
return new Labels(labels);
}
Example usage:
status.getAlerts().toLabels()
Which gives you a very flexible and secure behaviour.
Though this is not a very generic solution, however, I think this will serve your purpose.
I would like to suggest you create an adapter for Gson which can convert the map values for you. The adapter might look like the following.
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
final class GSONAdapter implements JsonDeserializer<String> {
private static final GSONAdapter instance = new GSONAdapter();
static GSONAdapter instance() {
return instance;
}
#Override
public String deserialize(JsonElement jsonElement, Type type,
JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
// Here I am taking the elements which are starting with field
// and then returning the lowercase version
// so that the labels map is created this way
if (jsonElement.getAsString().toLowerCase().startsWith("field"))
return jsonElement.getAsString().toLowerCase();
else return jsonElement.getAsString();
}
}
Now just add the GsonBuilder to your Gson using the adapter and then try to parse the JSON. You should get all the values in the lower case as you wanted for the labels.
Please note that I am just taking the field variables in my concern and hence this is not a generic solution which will work for every key. However, if your keys have any specific format, this can be easily applied.
Gson gson = new GsonBuilder()
.registerTypeAdapter(String.class, GSONAdapter.instance())
.create();
Status status = gson.fromJson(statusJSONString, Status.class);
Alerts alerts = status.getAlerts();
Hope that solves your problem.
I was just wondering, given a pojo:
public class MyProfileDto {
private List<String> skills;
//mutators; getSkills; setSkills + bunch of other fields
}
and JSON for the skills field:
"skills":{
"values":[
{
"id":14,
"skill":{
"name":"C++"
}
},
{
"id":15,
"skill":{
"name":"Java"
}
}
],
"_total":2
}
Is there any way using Jackson to get the skills/values/skill/name field (i.e. "Java", "C++") into the target Dto's String List without creating a custom deserializer for the entire Dto? It has many fields so an ideal solution would involve some custom annotation or deserializer for the one field if possible??
Jackson does not contains any XPath feature but you can define converter for each property. This converter will be used by Jackson to convert input type to output type which you need. In your example input type is Map<String, Object> and output type is List<String>. Probably, this is not the simplest and the best solution which we can use but it allows us to define converter for only one property without defining deserializer for entire entity.
Your POJO class:
class MyProfileDto {
#JsonDeserialize(converter = SkillConverter.class)
private List<String> skills;
public List<String> getSkills() {
return skills;
}
public void setSkills(List<String> skills) {
this.skills = skills;
}
}
Converter for List<String> skills; property:
class SkillConverter implements Converter<Map<String, Object>, List<String>> {
#SuppressWarnings("unchecked")
public List<String> convert(Map<String, Object> value) {
Object values = value.get("values");
if (values == null || !(values instanceof List)) {
return Collections.emptyList();
}
List<String> result = new ArrayList<String>();
for (Object item : (List<Object>) values) {
Map<String, Object> mapItem = (Map<String, Object>) item;
Map<String, Object> skillMap = (Map<String, Object>) mapItem.get("skill");
if (skillMap == null) {
continue;
}
result.add(skillMap.get("name").toString());
}
return result;
}
public JavaType getInputType(TypeFactory typeFactory) {
return typeFactory.constructMapLikeType(Map.class, String.class, Object.class);
}
public JavaType getOutputType(TypeFactory typeFactory) {
return typeFactory.constructCollectionLikeType(List.class, String.class);
}
}
And example usage:
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.databind.util.Converter;
public class JacksonProgram {
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
MyProfileDto dto = mapper.readValue(new File("/x/json"), MyProfileDto.class);
System.out.println(dto.getSkills());
}
}
Above program prints:
[C++, Java]
I've got this JSON : {"success":false}
I want to deserialize this into this POJO :
class Message {
private Map<String, String> dataset = new HashMap<String, String>();
#JsonProperty("success")
public boolean isSuccess() {
return Boolean.valueOf(dataset.get("success"));
}
#JsonProperty("success")
public void setSuccess(boolean success) {
dataset.put("success", String.valueOf(success));
}
}
Is it possible to deserialize this JSON into a class without field success?
So far, i've always got the "UnrecognizedPropertyException: Unrecognized field "success""
Thanks for your help!
You could implement a method and annotate it with #JsonAnySetter like this:
#JsonAnySetter
public void handleUnknownProperties(String key, Object value) {
// this will be invoked when property isn't known
}
another possibility would be turn this fail off like this:
objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
This would let you deserialize your JSON without failing when properties are not found.
Test
public static class Message {
private final Map<String, String> dataset = new HashMap<String, String>();
#Override
public String toString() {
return "Message [dataset=" + dataset + "]";
}
}
#Test
public void testJackson() throws JsonParseException, JsonMappingException, IOException {
String json = "{\"success\":false}";
ObjectMapper om = new ObjectMapper().configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
System.out.println(om.readValue(json, Message.class));
}
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
If you can't get it to work with Jackson, below is how you can support this use case with MOXy.
Message
No annotations are required on the Message class. By default property access is used. You can specify field access using #XmlAccessorType(XmlAccessType.FIELD), see: http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html.
package forum11315389;
import java.util.*;
class Message {
private Map<String, String> dataset = new HashMap<String, String>();
public boolean isSuccess() {
return Boolean.valueOf(dataset.get("success"));
}
public void setSuccess(boolean success) {
dataset.put("success", String.valueOf(success));
}
}
jaxb.properties
To specify MOXy as your JAXB provider you need to include a file called jaxb.properties in the same package as your domain model with the following entry:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
package forum11315389;
import java.io.StringReader;
import java.util.*;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String,Object> properties = new HashMap<String,Object>(1);
properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
JAXBContext jc = JAXBContext.newInstance(new Class[] {Message.class}, properties);
StreamSource json = new StreamSource(new StringReader("{\"success\":false}"));
Unmarshaller unmarshaller = jc.createUnmarshaller();
Message message = unmarshaller.unmarshal(json, Message.class).getValue();
Marshaller marshaller = jc.createMarshaller();
marshaller.marshal(message, System.out);
}
}
Input/Output
{"success":false}
I don't understand the question. Jackson will (de)serialize from/to the current version of the Message POJO you've defined in the original question just fine, without errors, and without any special configurations (other than the #JsonProperty annotations). The current Message POJO does not have a field named success, but it does define a property named success, which is why Jackson is happy to map the example JSON to it without any additional configurations. Are you wanting to remove the #JsonProperty annotations?
If that's the case, then you can do so, and Jackson will still (de)serialize from/to the Message POJO with the same example JSON without any other configurations necessary, because the isSuccess and setSuccess method signatures already adequately define that Message has a property named success, which matches the element name in the JSON.
The following examples demonstrate these points.
Example 1 with Message POJO exactly as defined in original question:
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonFoo
{
public static void main(String[] args) throws Exception
{
// input: {"success":false}
String inputJson = "{\"success\":false}";
ObjectMapper mapper = new ObjectMapper();
Message message = mapper.readValue(inputJson, Message.class);
System.out.println(mapper.writeValueAsString(message));
// output: {"success":false}
}
}
class Message
{
private Map<String, String> dataset = new HashMap<String, String>();
#JsonProperty("success")
public boolean isSuccess()
{
return Boolean.valueOf(dataset.get("success"));
}
#JsonProperty("success")
public void setSuccess(boolean success)
{
dataset.put("success", String.valueOf(success));
}
}
Example 2 with Message POJO modified to remove #JsonProperty annotations.
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonFoo
{
public static void main(String[] args) throws Exception
{
// input: {"success":false}
String inputJson = "{\"success\":false}";
ObjectMapper mapper = new ObjectMapper();
Message message = mapper.readValue(inputJson, Message.class);
System.out.println(mapper.writeValueAsString(message));
// output: {"success":false}
}
}
class Message
{
private Map<String, String> dataset = new HashMap<String, String>();
public boolean isSuccess()
{
return Boolean.valueOf(dataset.get("success"));
}
public void setSuccess(boolean success)
{
dataset.put("success", String.valueOf(success));
}
}
Example with MessageWrapper:
public class JacksonFoo
{
public static void main(String[] args) throws Exception
{
// input: {"success":false}
String inputJson = "{\"success\":true}";
ObjectMapper mapper = new ObjectMapper();
MessageWrapper wrappedMessage = mapper.readValue(inputJson, MessageWrapper.class);
System.out.println(mapper.writeValueAsString(wrappedMessage));
// output: {"success":true}
}
}
class MessageWrapper
{
#JsonUnwrapped
#JsonProperty // exposes non-public field for Jackson use
Message message;
}