I am having a map
Map<String, Application.RiskFactor> appRiskFactorsMap = app.getRiskFactors();
It has this data kind of in it
{risk1=Application.RiskFactor(risk=risk1, question=question1,
factor=true), risk2=Application.RiskFactor(risk=risk2,
question=question2?, factor=true),
risk3=Application.RiskFactor(risk=risk3, question=question3?,
factor=true)}
I am converting it into JSON and having this output.
{"risk1":{"risk":"risk1","question":"question1?","factor":"true"},"":
{"risk":"risk2","question":"question2?","factor":"true"},"risk3":
{"risk":"risk3","question":"question3?","factor":"true"}}
I have this JSON converter class
package system.referee.util;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
public final class JsonUtils {
private static final ObjectMapper MAPPER = new ObjectMapper();
static {
// Ignore unknown fields while deserialization
MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// Ignore null & Optional.EMPTY fields while serialization
MAPPER.setSerializationInclusion(JsonInclude.Include.NON_ABSENT);
}
public static <T> String toJson(T obj) {
try {
return MAPPER.writeValueAsString(obj);
} catch (JsonProcessingException e) {
return "";
}
}
public static <T> T fromJson(String json, Class<T> type) {
try {
return MAPPER.readValue(json, type);
} catch (JsonProcessingException e) {
return null;
}
}
}
I want to print the JSON in this format
{"risk":"risk1","question":"question1?","factor":"true"},
{"risk":"risk2","question":"question2?","factor":"true"},
{"risk":"risk3","question":"question3?","factor":"true"}
is there any way to achieve that? I am unable to find any help with this. thanks a lot
You should ignore keys and serialise only values:
JsonUtils.toJson(appRiskFactorsMap.values())
Result will be a JSON Array.
Related
I'm struggling to deserialize a Collection<Collection<?>> using Jackson. When deserializing the serialized object Jackson converts them into a LinkedHashMap instead of Item:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class JsonTest {
ObjectMapper mapper = new ObjectMapper();
#Test
void main() throws JsonProcessingException {
Set<Integer> firstSet = Set.of(1, 2, 3);
Set<Item> secondSet = Set.of(new Item("abc"), new Item("123"));
Root root = new Root(List.of(firstSet, secondSet));
String json = mapper.writeValueAsString(root);
System.out.println(json);
Root parsed = mapper.readValue(json, Root.class);
assertEquals(firstSet, parsed.data().get(0));
assertEquals(secondSet, parsed.data().get(1));
// the assertion above fails:
// Expected :[Item[id=abc], Item[id=123]]
// Actual :[{id=abc}, {id=123}]
}
}
record Root(List<Set<?>> data) {}
record Item(String id) {}
// build.gradle
plugins {
id 'java'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}
test {
useJUnitPlatform()
}
My first idea was to replace the Set<?> with a custom container class that contains an additional type hint and write a custom deserializer:
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class JsonTest {
ObjectMapper mapper = new ObjectMapper();
#Test
void main() throws JsonProcessingException {
TypedList<Item> secondSet = new TypedList<>(Item.class, List.of());
Root root = new Root(secondSet);
String json = mapper.writeValueAsString(root);
System.out.println(json);
Root parsed = mapper.readValue(json, Root.class);
assertEquals(secondSet, parsed.data());
}
}
class TypedCollectionDeserializer<T> extends StdDeserializer<TypedList<T>> {
public TypedCollectionDeserializer() {
super(TypedList.class);
}
#Override
public TypedList<T> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
Class<T> valueType = getTypeClass(p);
String dataKey = p.nextFieldName();
if (!dataKey.equals("data")) {
throw new IllegalStateException();
}
List<T> list = deserializeData(p, valueType);
// skip END_ARRAY
p.nextToken();
return new TypedList<>(valueType, list);
}
private Class<T> getTypeClass(JsonParser p) throws IOException {
String typeKey = p.nextFieldName();
if (!typeKey.equals("type")) {
throw new IllegalStateException();
}
String typeValue = p.nextTextValue();
try {
return (Class<T>) Class.forName(typeValue);
} catch (ClassNotFoundException e) {
throw new IllegalStateException("unexpected type " + typeValue, e);
}
}
private List<T> deserializeData(JsonParser p, Class<T> valueType) throws IOException {
List<T> list = new ArrayList<>();
JsonToken jsonToken = p.nextToken();
if (jsonToken != JsonToken.START_ARRAY) {
throw new IllegalArgumentException();
}
JsonToken maybeStart = p.nextToken();
if (maybeStart == JsonToken.START_OBJECT) {
do {
T t = p.readValueAs(valueType);
if (t != null) {
list.add(t);
}
} while (p.nextToken() == JsonToken.START_OBJECT);
}
return list;
}
}
record Root(#JsonDeserialize(using = TypedCollectionDeserializer.class) TypedList<?> data) {}
record Item(String id) {}
#JsonPropertyOrder({"type", "data"})
record TypedList<T>(Class<T> type, List<T> data) {}
But this looks like I'm re-doing Jackson's own code to deserialize Collections. Is there perhaps a more idiomatic way?
I created a model:
public class UserRequest extends DefaultRequest {
public String username;
public String password;
public String id;
public UserRequest(String username, String password) {
this.username = username;
this.password = password;
}
}
And I'm calling it like:
//code truncated
UserRequest userRequest = new UserRequest(username,password);
response = getRestClient().sysInitApp(userRequest).execute();
//code truncated
And then I print out request body, instead of:
{
"username":"farid",
"password":"passfarid",
"id":null
}
I get:
{
"username":"farid",
"password":"passfarid"
}
I would appreciate any help with this issue.
from the GsonBuilder javadocs... you can use GsonBuilder to construct your Gson instance, and opt in to have null values serialized as so:
Gson gson = new GsonBuilder()
.serializeNulls()
.create();
Not too familiar with Gson, but I don't think Gson would write null values to an json file. If you initialize the id like:
String id = "";
you may get an empty string in there. But you will not get a null value into a .xml file.
An example of how to enforce outputting values even if null. It will output the empty string (or "{}" if an object) instead of null and ignore transients:
package unitest;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
public class TheResponse<T> {
private String status;
private String message;
private T data;
transient private String resource;
public static void main(String[] args) {
TheResponse<String> foo = new TheResponse<String>();
//TheResponse<Baz> foo = new TheResponse<Baz>();
foo.status = "bar";
foo.data = "baz";
Gson gson = new GsonBuilder().registerTypeAdapter(TheResponse.class, new GenericAdapter()).create();
System.out.println(gson.toJson(foo).toString());
}
public static class GenericAdapter extends TypeAdapter<Object> {
#Override
public void write(JsonWriter jsonWriter, Object o) throws IOException {
recursiveWrite(jsonWriter, o);
}
private void recursiveWrite(JsonWriter jsonWriter, Object o) throws IOException {
jsonWriter.beginObject();
for (Field field : o.getClass().getDeclaredFields()) {
boolean isTransient = Modifier.isTransient(field.getModifiers());
if (isTransient) {
continue;
}
Object fieldValue = null;
try {
field.setAccessible(true);
fieldValue = field.get(o);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
jsonWriter.name(field.getName());
if (fieldValue != null && fieldValue.getClass() != String.class) {
recursiveWrite(jsonWriter, fieldValue);
continue;
}
if (fieldValue == null) {
if (field.getType() == String.class)
jsonWriter.value("");
else {
jsonWriter.jsonValue("{}");
}
} else {
jsonWriter.value(fieldValue.toString());
}
}
jsonWriter.endObject();
}
#Override
public Object read(JsonReader jsonReader) throws IOException {
// todo
return null;
}
}
}
I am trying to write an abstract class which will map the string values to the object member-variables and vice versa using ObjectMapper of jackson-databind. This abstract class will be extended by each pojo of json.
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public abstract class JsonToString {
public JsonToString toObject(String jsonString){
ObjectMapper mapper = new ObjectMapper();
try {
mapper.readValue(jsonString, this.getClass());//problem
System.out.println("inside object function of jsontostring : "+this);
} catch (JsonParseException e) {
System.out.println("Exception occured in mapping jsonString received to object" + e);
} catch (JsonMappingException e) {
System.out.println("Exception occured in mapping jsonString received to object" + e);
} catch (IOException e) {
System.out.println("Exception occured in mapping jsonString received to object" + e);
}
return this;
}
public String toString(){
ObjectMapper mapper = new ObjectMapper();
String json = new String();
try {
json = mapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
System.out.println("Trouble in mapping object to string in json class : "+this.getClass().getName());
}
return json;
}
}
this class will be extended by each json pojo.
So here I want to return the object of child class for which the mappings has been done. Can someone please help me get the object and return it.
I am calling this method in this manner :
ITAGResponseInfo response = new ITAGResponseInfo();
response = (ITAGResponseInfo)response.toObject(cOutput);
System.out.println("Printing from the itagresponseinfo object : "+response);
Here ITAGResponseInfo extends the JsonToString class.
i need to convert a POJO to a JSONObject (org.json.JSONObject)
I know how to convert it to a file:
ObjectMapper mapper = new ObjectMapper();
try {
mapper.writeValue(new File(file.toString()), registrationData);
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
But I dont want a file this time.
If we are parsing all model classes of server in GSON format then this is a best way to convert java object to JSONObject.In below code SampleObject is a java object which gets converted to the JSONObject.
SampleObject mSampleObject = new SampleObject();
String jsonInString = new Gson().toJson(mSampleObject);
JSONObject mJSONObject = new JSONObject(jsonInString);
If it's not a too complex object, you can do it yourself, without any libraries. Here is an example how:
public class DemoObject {
private int mSomeInt;
private String mSomeString;
public DemoObject(int i, String s) {
mSomeInt = i;
mSomeString = s;
}
//... other stuff
public JSONObject toJSON() {
JSONObject jo = new JSONObject();
jo.put("integer", mSomeInt);
jo.put("string", mSomeString);
return jo;
}
}
In code:
DemoObject demo = new DemoObject(10, "string");
JSONObject jo = demo.toJSON();
Of course you can also use Google Gson for more complex stuff and a less cumbersome implementation if you don't mind the extra dependency.
The example below was pretty much lifted from mkyongs tutorial. Instead of saving to a file you can just use the String json as a json representation of your POJO.
import java.io.FileWriter;
import java.io.IOException;
import com.google.gson.Gson;
public class GsonExample {
public static void main(String[] args) {
YourObject obj = new YourOBject();
Gson gson = new Gson();
String json = gson.toJson(obj); //convert
System.out.println(json);
}
}
Here is an easy way to convert Java object to JSON Object (not Json String)
import com.fasterxml.jackson.databind.ObjectMapper;
import org.json.simple.parser.JSONParser;
JSONObject jsonObject = (JSONObject) JSONValue.parse(new ObjectMapper().writeValueAsString(JavaObject));
How to get JsonElement from Object:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.*;
final ObjectMapper objectMapper = new ObjectMapper();
final Gson gson = new Gson();
String json = objectMapper.writeValueAsString(source);
JsonElement result = gson.fromJson(json, JsonElement.class);
I have a complex JSON that I am trying to parse using Jackson JSON. I am a little confused about how to get into the latLng object to pull out the lat,lng values. This is part of the JSON:
{
"results": [
{
"locations": [
{
"latLng": {
"lng": -76.85165,
"lat": 39.25108
},
"adminArea4": "Howard County",
"adminArea5Type": "City",
"adminArea4Type": "County",
This is what I have so far in Java to pull it out:
public class parkJSON
{
public latLng _latLng;
public static class latLng
{
private String _lat, _lng;
public String getLat() { return _lat; }
public String getLon() { return _lng; }
}
}
and
ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
parkJSON geo = mapper.readValue(parse, parkJSON.class);
System.out.println(mapper.writeValueAsString(geo));
String lat = geo._latLng.getLat();
String lon = geo._latLng.getLon();
output = lat + "," + lon;
System.out.println("Found Coordinates: " + output);
RESOLVED This is how I solved the issue by using Tree Model for future reference:
ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JsonNode rootNode = mapper.readTree(parse);
JsonNode firstResult = rootNode.get("results").get(0);
JsonNode location = firstResult.get("locations").get(0);
JsonNode latLng = location.get("latLng");
String lat = latLng.get("lat").asText();
String lng = latLng.get("lng").asText();
output = lat + "," + lng;
System.out.println("Found Coordinates: " + output);
If all you're really interested in in this input structure are lat and lng full mapping is probably the least adapted of the different approaches offered by Jackson, as it forces you to write classes to represent the different layers in your data.
There are two alternatives offered by Jackson that will allow you to extract these fields without having to define these classes:
The tree model offers a number of navigation methods to traverse the tree and extract the data you're interested in.
Simple data binding maps the JSON document onto a Map or a List which can then be navigated with the methods offered by these collections.
The Jackson documentation contains examples for both techniques, applying them in your program should not be too hard, use your debugger to investigate the data structures created by the parser to see how the document got mapped.
whatever your json: here is an utility which is up to transform json2object or Object2json,
import java.io.IOException;
import java.io.StringWriter;
import java.util.List;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
/**
*
* #author TIAGO.MEDICI
*
*/
public class JsonUtils {
public static boolean isJSONValid(String jsonInString) {
try {
final ObjectMapper mapper = new ObjectMapper();
mapper.readTree(jsonInString);
return true;
} catch (IOException e) {
return false;
}
}
public static String serializeAsJsonString(Object object) throws JsonGenerationException, JsonMappingException, IOException {
ObjectMapper objMapper = new ObjectMapper();
objMapper.enable(SerializationFeature.INDENT_OUTPUT);
objMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
StringWriter sw = new StringWriter();
objMapper.writeValue(sw, object);
return sw.toString();
}
public static String serializeAsJsonString(Object object, boolean indent) throws JsonGenerationException, JsonMappingException, IOException {
ObjectMapper objMapper = new ObjectMapper();
if (indent == true) {
objMapper.enable(SerializationFeature.INDENT_OUTPUT);
objMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
}
StringWriter stringWriter = new StringWriter();
objMapper.writeValue(stringWriter, object);
return stringWriter.toString();
}
public static <T> T jsonStringToObject(String content, Class<T> clazz) throws JsonParseException, JsonMappingException, IOException {
T obj = null;
ObjectMapper objMapper = new ObjectMapper();
obj = objMapper.readValue(content, clazz);
return obj;
}
#SuppressWarnings("rawtypes")
public static <T> T jsonStringToObjectArray(String content) throws JsonParseException, JsonMappingException, IOException {
T obj = null;
ObjectMapper mapper = new ObjectMapper();
obj = mapper.readValue(content, new TypeReference<List>() {
});
return obj;
}
public static <T> T jsonStringToObjectArray(String content, Class<T> clazz) throws JsonParseException, JsonMappingException, IOException {
T obj = null;
ObjectMapper mapper = new ObjectMapper();
mapper = new ObjectMapper().configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
obj = mapper.readValue(content, mapper.getTypeFactory().constructCollectionType(List.class, clazz));
return obj;
}