I have a simple directed graph from jgrapht and I am trying to serialize it into a JSON file using jackson as follows:
ObjectMapper mapper = new ObjectMapper();
File output = new File("P:\\tree.json");
ObjectWriter objectWriter = mapper.writer().withDefaultPrettyPrinter();
objectWriter.writeValue(output,simpleDirectedGraph);
However I get this error:
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class org.jgrapht.graph.AbstractBaseGraph$ArrayListFactory and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: org.jgrapht.graph.SimpleDirectedGraph["edgeSetFactory"])
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:69)
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:32)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:693)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:675)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:130)
at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1387)
at com.fasterxml.jackson.databind.ObjectWriter._configAndWriteValue(ObjectWriter.java:1088)
at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:909)
at ms.fragment.JSONTreeGenerator.main(JSONTreeGenerator.java:45)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
I have seen that there is a GmlExporter but I am interested in json... how can I do that?
You can disable the exception with:
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
The exception you got from Jackson:
JsonMappingException: No serializer found for class org.jgrapht.graph.AbstractBaseGraph$ArrayListFactory
and no properties discovered to create BeanSerializer
(to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)) (through reference chain:
org.jgrapht.graph.SimpleDirectedGraph["edgeSetFactory"])
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:69)
gives a clue on how to solve:
no properties discovered to create BeanSerializer
property SimpleDirectedGraph["edgeSetFactory"] seems empty
Exclude the type of property edgeSetFactory from serialisation:
AbstractBaseGraph$ArrayListFactory
Write a custom Serializer
Usually Jackson would use a StdBeanSerializer to write any non-primitive class to JSON.
Unfortunately this does not work for abstract classes.
So you can write your own JsonSerializer to handle special fields.
You can serialize your Graph to XML and then from XML to JSON :
Serialization to XML : you can use this Library: XStream http://x-stream.github.io it's a small library that will easily allow you to serialize and deserialize to and from XML.
guide to use the Library : http://x-stream.github.io/tutorial.html
After that try to map your XML to JSON using :
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20180813</version>
</dependency>
XML.java is the class you're looking for:
import org.json.JSONObject;
import org.json.XML;
import org.json.JSONException;
public class Main {
public static int PRETTY_PRINT_INDENT_FACTOR = 4;
public static String TEST_XML_STRING =
"<?xml version=\"1.0\" ?><test attrib=\"moretest\">Turn this to JSON</test>";
public static void main(String[] args) {
try {
JSONObject xmlJSONObj = XML.toJSONObject(TEST_XML_STRING);
String jsonPrettyPrintString = xmlJSONObj.toString(PRETTY_PRINT_INDENT_FACTOR);
System.out.println(jsonPrettyPrintString);
} catch (JSONException je) {
System.out.println(je.toString());
}
}
}
Option 1
Newer versions of JGraphT have built-in support for importing/exporting graphs from/to JSON using the jgrapht-io
module.
Here's an example for exporting a graph to JSON:
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.nio.json.JSONExporter;
import java.net.URI;
import java.net.URISyntaxException;
public class Main {
public static void main(String[] args) throws Exception {
final var jsonExporter = new JSONExporter<URI, DefaultEdge>();
jsonExporter.exportGraph(
newSampleGraph(),
System.out
);
System.out.println("");
}
// Copied from https://jgrapht.org/guide/HelloJGraphT
private static Graph<URI, DefaultEdge> newSampleGraph() throws URISyntaxException {
Graph<URI, DefaultEdge> g = new DefaultDirectedGraph<>(DefaultEdge.class);
URI google = new URI("http://www.google.com");
URI wikipedia = new URI("http://www.wikipedia.org");
URI jgrapht = new URI("http://www.jgrapht.org");
// add the vertices
g.addVertex(google);
g.addVertex(wikipedia);
g.addVertex(jgrapht);
// add edges to create linking structure
g.addEdge(jgrapht, wikipedia);
g.addEdge(google, jgrapht);
g.addEdge(google, wikipedia);
g.addEdge(wikipedia, google);
return g;
}
}
The pom.xml file for reference:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.stackoverflow</groupId>
<artifactId>questions-39438962</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>18</maven.compiler.source>
<maven.compiler.target>18</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.jgrapht</groupId>
<artifactId>jgrapht-core</artifactId>
<version>1.5.1</version>
</dependency>
<dependency>
<groupId>org.jgrapht</groupId>
<artifactId>jgrapht-io</artifactId>
<version>1.5.1</version>
</dependency>
</dependencies>
</project>
Option 2
Implement a custom Jackson serializer for JGraphT graphs, register it with an ObjectMapper, and implement the logic in the serializer.
Here's an example:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import org.jgrapht.Graph;
import org.jgrapht.nio.IntegerIdProvider;
import java.io.IOException;
public class DefaultDirectedGraphSerializer<V, E, T extends Graph<V, E>> extends StdSerializer<T> {
public DefaultDirectedGraphSerializer(Class<T> t) {
super(t);
}
public DefaultDirectedGraphSerializer() {
this(null);
}
#Override
public void serialize(T value, JsonGenerator gen, SerializerProvider provider) throws IOException {
final var idProvider = new IntegerIdProvider<>();
gen.writeStartObject();
gen.writeFieldName("graph");
gen.writeStartObject();
gen.writeFieldName("nodes");
gen.writeStartObject();
for (V v : value.vertexSet()) {
final var id = idProvider.apply(v);
gen.writeFieldName(id);
gen.writeStartObject();
gen.writeStringField("label", v.toString());
gen.writeEndObject();
}
gen.writeEndObject();
gen.writeFieldName("edges");
gen.writeStartArray();
for (E e : value.edgeSet()) {
gen.writeStartObject();
final var source = value.getEdgeSource(e);
final var target = value.getEdgeTarget(e);
gen.writeStringField("source", idProvider.apply(source));
gen.writeStringField("target", idProvider.apply(target));
gen.writeEndObject();
}
gen.writeEndArray();
gen.writeEndObject();
gen.writeEndObject();
}
}
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.graph.DefaultEdge;
import java.net.URI;
import java.net.URISyntaxException;
public class Graphs {
public static Graph<URI, DefaultEdge> newSampleGraph() throws URISyntaxException {
final var g = new DefaultDirectedGraph<URI, DefaultEdge>(DefaultEdge.class);
URI google = new URI("http://www.google.com");
URI wikipedia = new URI("http://www.wikipedia.org");
URI jgrapht = new URI("http://www.jgrapht.org");
g.addVertex(google);
g.addVertex(wikipedia);
g.addVertex(jgrapht);
g.addEdge(jgrapht, wikipedia);
g.addEdge(google, jgrapht);
g.addEdge(google, wikipedia);
g.addEdge(wikipedia, google);
return g;
}
}
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.jgrapht.graph.DefaultDirectedGraph;
import java.net.URISyntaxException;
import static org.example.Graphs.newSampleGraph;
public class Main {
public static void main(String[] args) throws URISyntaxException, JsonProcessingException {
final var module = new SimpleModule();
module.addSerializer(DefaultDirectedGraph.class, new DefaultDirectedGraphSerializer<>());
final ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
System.out.println(mapper.writeValueAsString(newSampleGraph()));
}
}
This will produce the following JSON document (after pretty printing):
{
"graph": {
"nodes": {
"1": {
"label": "http://www.google.com"
},
"2": {
"label": "http://www.wikipedia.org"
},
"3": {
"label": "http://www.jgrapht.org"
}
},
"edges": [
{
"source": "3",
"target": "2"
},
{
"source": "1",
"target": "3"
},
{
"source": "1",
"target": "2"
},
{
"source": "2",
"target": "1"
}
]
}
}
import org.jgrapht.Graph;
import org.jgrapht.io.JSONExporter;
import org.jgrapht.io.SimpleGraphExporter;
import org.jgrapht.io.SimpleGraphImporter;
import org.jgrapht.io.JSONImporter;
import org.jgrapht.io.JSONExporter;
import org.jgrapht.io.ExportException;
import org.jgrapht.io.ImportException;
// Create a new, empty simple graph
Graph<String, DefaultEdge> graph = new SimpleGraph<>(DefaultEdge.class);
// Add some vertices and edges to the graph
graph.addVertex("A");
graph.addVertex("B");
graph.addVertex("C");
graph.addEdge("A", "B");
graph.addEdge("B", "C");
// Create a new JSONExporter instance
JSONExporter<String, DefaultEdge> exporter = new JSONExporter<>();
// Export the graph to JSON
String json = exporter.toJson(graph);
Related
I try to convert a JSON into an XML with the following code
final ObjectMapper objectMapper = new ObjectMapper();
final XmlMapper xmlMapper = new XmlMapper();
JsonNode jsonNode = objectMapper.readTree(jsonString);
String xmlString = xmlMapper
.writerWithDefaultPrettyPrinter()
.withRootName("rootname")
.writeValueAsString(jsonNode);
Basically it works. Does anyone know, how I can add a namespace to the serialized XML-attributes. I've no POJOs for the objects. The convert should generate from this
{
"Status" : "OK"
}
something like this:
<ns2:rootname xmlns:ns2="http://whatever-it-is.de/">
<ns2:state>OK</ns2:state>
</ns2:rootname>
just create a pojo and add jackson annotations, e.g.
#JacksonXmlProperty(localName="ns2:http://whatever-it-is.de/")
public class Status {
// ...
}
Or if you want to go without a pojo try a custom serializer which adds namespaces
https://www.baeldung.com/jackson-custom-serialization
You need to provide custom Json Node serialiser and use ToXmlGenerator. See below example:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import javax.xml.namespace.QName;
import java.io.IOException;
public class XmlMapperApp {
public static void main(String... args) throws Exception {
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);
ObjectNode node = xmlMapper.createObjectNode()
.put("Status", "OK")
.set("node", xmlMapper.createObjectNode()
.put("int", 1)
.put("str", "str"));
SimpleModule module = new SimpleModule();
module.setSerializerModifier(new BeanSerializerModifier() {
#Override
public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {
if (beanDesc.getType().getRawClass().equals(ObjectNode.class)) {
return new ObjectNodeJsonSerializer(serializer);
}
return super.modifySerializer(config, beanDesc, serializer);
}
});
xmlMapper.registerModule(module);
System.out.println(xmlMapper.writeValueAsString(node));
}
}
class ObjectNodeJsonSerializer extends JsonSerializer<JsonNode> {
private final JsonSerializer baseSerializer;
ObjectNodeJsonSerializer(JsonSerializer baseSerializer) {
this.baseSerializer = baseSerializer;
}
#Override
public void serialize(JsonNode value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
ToXmlGenerator xmlGenerator = (ToXmlGenerator) gen;
xmlGenerator.setNextName(new QName("http://whatever-it-is.de/", "rootname", "anything"));
baseSerializer.serialize(value, gen, serializers);
}
}
Above example prints:
<wstxns1:rootname xmlns:wstxns1="http://whatever-it-is.de/">
<wstxns1:Status>OK</wstxns1:Status>
<wstxns1:node>
<wstxns1:int>1</wstxns1:int>
<wstxns1:str>str</wstxns1:str>
</wstxns1:node>
</wstxns1:rootname>
Underscore-java library can convert JSON to XML with namespace.
{
"ns2:rootname": {
"-xmlns:ns2": "http://whatever-it-is.de/",
"ns2:state": "OK"
},
"#omit-xml-declaration": "yes"
}
<ns2:rootname xmlns:ns2="http://whatever-it-is.de/">
<ns2:state>OK</ns2:state>
</ns2:rootname>
I am trying to create a JSON using the Jackson Streaming API. I know how to create an array of elements in JSON using Jackson as we have plenty of examples related to it. But I am a bit confused about how to create an array of Objects using it.
Following is the JSON structure that I would like to obtain at the end:
{
"name" : "Batman",
"year" : 2008,
"writers":[
{
"name" : "Nolan",
"age" : 49
},
{
"name" : "Johnathan",
"age" : 35
}
]
}
Following is the code I have:
import org.json.JSONObject;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
public class HelloWorld {
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
ByteArrayOutputStream jsonStream = new ByteArrayOutputStream();
JsonGenerator jsonGenerator = mapper.getFactory().createGenerator(jsonStream, JsonEncoding.UTF8);
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("name", "Batman");
jsonGenerator.writeNumberField("year", 2008);
jsonGenerator.writeFieldName("writers");
jsonGenerator.writeStartArray();
// How to to create here objects and add it to the "writers"
// Should I create another JsonGenerator and create objects usign it?
jsonGenerator.writeEndArray();
jsonGenerator.writeEndObject();
jsonGenerator.close();
String jsonData = new String(jsonStream.toByteArray(), "UTF-8");
JSONObject json = new JSONObject(jsonData);
System.out.println(json.toString(4));
}
}
Can someone please guide me on how to create the objects and add them to the array one by one? I am unable to find such an example so posting here.
I would just create a Map to store the data. For the writers, you can call List.of to create an in-line List.
import java.io.*;
import java.util.*;
import com.fasterxml.jackson.databind.*;
public class MovieDataWriter {
public static void main(String[] args) {
Map<String, Object> movieData = createMap(
"name", "Batman",
"year", 2008,
"writers", List.of(
createMap(
"name", "Nolan",
"age", 49
),
createMap(
"name", "Johnathan",
"age", 35
)
)
);
writeToFile(movieData, "target/batman.json");
}
private static void writeToFile(Map<String, Object> data, String filename) {
ObjectMapper mapper = new ObjectMapper();
ObjectWriter writer = mapper.writerWithDefaultPrettyPrinter();
try {
writer.writeValue(new File(filename), data);
} catch (IOException e) {
e.printStackTrace();
}
}
private static Map<String, Object> createMap(Object ...args) {
Map<String, Object> pairs = new LinkedHashMap<>();
for (int i = 0; i < args.length; i += 2) {
pairs.put(String.valueOf(args[i]), args[i + 1]);
}
return pairs;
}
}
Dependencies
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.1</version>
</dependency>
batman.json
{
"name" : "Batman",
"year" : 2008,
"writers" : [ {
"name" : "Nolan",
"age" : 49
}, {
"name" : "Johnathan",
"age" : 35
} ]
}
After trying a few things I was able to get it. Basically, I had to do the same thing which I was asked in the question. I am not sure why it did not work the first time maybe I missed something. Anyways here is how you can add objects into the array using the Jackson Streaming API. Posting this as it can be beneficial to someone else in the future.
I am creating an array writers in this case and adding the objects into it using the same jsonGenerator.
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.json.JSONObject;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
public class HelloWorld {
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
ByteArrayOutputStream jsonStream = new ByteArrayOutputStream();
JsonGenerator jsonGenerator = mapper.getFactory().createGenerator(jsonStream, JsonEncoding.UTF8);
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("name", "Batman");
jsonGenerator.writeNumberField("year", 2008);
jsonGenerator.writeFieldName("writers");
jsonGenerator.writeStartArray();
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("name", "Nolan");
jsonGenerator.writeNumberField("age", 45);
jsonGenerator.writeEndObject();
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("name", "Johanathan");
jsonGenerator.writeNumberField("age", 35);
jsonGenerator.writeEndObject();
jsonGenerator.writeEndArray();
jsonGenerator.writeEndObject();
jsonGenerator.close();
String jsonData = new String(jsonStream.toByteArray(), "UTF-8");
JSONObject json = new JSONObject(jsonData);
System.out.println(json.toString(4));
}
}
You will get the output something like this:
{
"year": 2008,
"name": "Batman",
"writers": [
{
"name": "Nolan",
"age": 45
},
{
"name": "Johanathan",
"age": 35
}
]
}
I have a Java TreeMap frutitas inside a custom object on the server side which I want to send to the frontend.
I use javax.ws and jackson to serialise. The data that I get in the frontend looks like this:
{ "frutitas": {
"entry": [
{
"key": "fruto 1",
"value": "el banano"
},
{
"key": "fruto 2",
"value": "el pineapple"
}
]
}
But I want to get something like this, which is actually how I send the "frutitas" map inside the object that I send to the backend when I want to upload it:
{
"frutitas": {
"fruto 1": "el banano",
"fruto 2": "el pineapple"
}
}
Another option is to use gson.
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
And the class containing the map:
public class FrutitasClass {
private Map<String, String> frutitas;
}
The code below would the conversion:
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(frutitasClassObject);
Out:
{
"frutitas": {
"fruto 1": "el banano",
"fruto 2": "el pineapple"
}
}
You can convert TreeMap to JSONObject as you expected. Here is the sample so that you can get the idea.
JSONObject jsonObject = new JSONObject(yourTreeMap);
If you print jsonObject, Output will be like this.
{"fruto 1":"el banan","fruto 2":"el pineapple"}
JSONObject main = new JSONObject();
main.put("frutitas", jsonObject);
{
"frutitas": {
"fruto 1": "el banano",
"fruto 2": "el pineapple"
}
}
Library Json-Jackson also known as FasterXML is de-facto standard for JSON serialization-deserialization. It works fast and is widely used. Below is a simple class that I wrote for serializing/de-serializing any Object. But in general you need to look at ObjectMapper class to see how it works. Here is Github link to a project. Here are Maven dependencies you may use:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.9.9</version>
</dependency>
My Class Example
package com.bla.json.utils;
import java.io.IOException;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
public class JsonUtil {
private static final ObjectReader objectReader;
private static final ObjectWriter objectWriter;
static {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModules(new JavaTimeModule());
objectMapper.enableDefaultTyping();
objectReader = objectMapper.reader();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectWriter = objectMapper.writer();
}
public static String writeObjectToJsonString(Object object) throws JsonProcessingException {
String jsonData = null;
if (object != null) {
jsonData = objectWriter.writeValueAsString(object);
}
return jsonData;
}
public static <T> T readObjectFromJsonString(String s, Class<T> type) throws IOException {
T data = objectReader.forType(type).readValue(s);
return data;
}
}
Wanted to covert an xml String to Json and I am doing it as below.
XML which has to be converted
<Item>
<Property name="Description" value="Description 1"/>
<Property name="EffDate" value="01/05/2017"/>
<Property name="ExpDate" value="12/31/9999"/>
<Property name="Status" value="Launched"/>
</Item>
I have created a Class for the xml as below.
public class Context {
#XmlElement(name = "Item")
private List<Item> offer;
}
public class Item {
#XmlElement(name = "Property")
private List<Property> properties;
}
public class Property {
#XmlAttribute
private String name;
#XmlAttribute
private String value;
}
I am using Gson libraries to convert this Java object to Json - g.toJson.
Comverted JSON -
"offer": [{
"properties": [{
"name": "Description",
"value": "Description 1"
},
{
"name": "EffDate",
"value": "01/05/2017"
},
{
"name": "ExpDate",
"value": "12/31/9999"
},
{
"name": "Status",
"value": "Launched"
}]
}]
But we wanted to convert the JSON as below -
"offer": [{
"Description" : "Description 1",
"EffDate":"01/05/2017",
"ExpDate": "12/31/9999",
"Status": "Launched"
}]
Is there a way to convert the properties name and value as Item class properties.?
Try using this link: https://github.com/stleary/JSON-java This is a JSON Helper class that can convert XML to JSON for example:
public class Main {
public static int PRETTY_PRINT_INDENT_FACTOR = 4;
public static String TEST_XML_STRING =
"<?xml version=\"1.0\" ?><test attrib=\"moretest\">Turn this to JSON</test>";
public static void main(String[] args) {
try {
JSONObject xmlJSONObj = XML.toJSONObject(TEST_XML_STRING);
String jsonPrettyPrintString = xmlJSONObj.toString(PRETTY_PRINT_INDENT_FACTOR);
System.out.println(jsonPrettyPrintString);
} catch (JSONException je) {
System.out.println(je.toString());
}
}
}
Hope this helps :)
It is possible using FasterXML library. where you can write your custom logic for generating XML and JSON. By overriding serialize of JsonSerializer class.
Need to write Serializer like :
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
public class ContextSerializer extends JsonSerializer<Context> {
#Override
public void serialize(Context t, JsonGenerator jg, SerializerProvider sp) throws IOException, JsonProcessingException {
jg.writeStartObject();
jg.writeArrayFieldStart("offer");
for (Item i : t.offer) {
jg.writeStartObject();
for (Property property : i.properties) {
jg.writeStringField(property.name, property.value);
}
jg.writeEndObject();
}
jg.writeEndArray();
jg.writeEndObject();
}
}
For convert:
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBException;
public class Main {
public static void main(String[] args) throws JAXBException, JsonProcessingException {
Context c = new Context();
List<Item> offer = new ArrayList<>();
Item pr = new Item();
pr.properties = new ArrayList<>();
Property p = new Property();
p.name = "asdf";
p.value = "va1";
pr.properties.add(p);
p = new Property();
p.name = "asdf1";
p.value = "va11";
pr.properties.add(p);
offer.add(pr);
c.offer = offer;
try {
SimpleModule module = new SimpleModule();
module.addSerializer(Context.class, new ContextSerializer());
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(module);
objectMapper.setSerializationInclusion(Include.NON_DEFAULT);
String json = objectMapper.writeValueAsString(c);
System.out.println(json);
} catch (Exception e) {
System.out.println(""+e);
}
}
}
O/P JSON : (Provided O/P JSON is wrong in your question if you give the name to the list("offer") then it always inside object link)
{
"offer": [{
"asdf": "va1",
"asdf1": "va11"
}
]
}
Maven Dependency for package is:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0.pr3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0.pr3</version>
</dependency>
If you are using Java 8 or later, you should check out my open source library: unXml. unXml basically maps from Xpaths to Json-attributes.
It's available on Maven Central.
Example
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.nerdforge.unxml.factory.ParsingFactory;
import com.nerdforge.unxml.parsers.Parser;
import org.w3c.dom.Document;
public class Parser {
public ObjectNode parseXml(String xml){
Parsing parsing = ParsingFactory.getInstance().create();
Document document = parsing.xml().document(xml);
Parser<ObjectNode> parser = parsing.obj("/")
.attribute("offer", parsing.arr("/Item")
.attribute("Description", "Property[#name='Description']/#value")
.attribute("EffDate", "Property[#name='EffDate']/#value")
.attribute("ExpDate", "Property[#name='ExpDate']/#value")
.attribute("Status", "Property[#name='Status']/#value")
)
.build();
ObjectNode result = parser.apply(document);
return result;
}
}
It will return a Jackson ObjectNode, with the following json:
{
"offer": [
{
"Status": "Launched",
"Description": "Description 1",
"ExpDate": "12/31/9999",
"EffDate": "01/05/2017"
}
]
}
You may convert xml to a map, modify it and then convert to a json. Underscore-java library has static methods U.fromXml(xml) and U.toJson(json). I am the maintainer of the project.
I wrote the following JsonSerializer to let Jackson serialize an array of integers into JSON:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
public class TalkIdsSerializer extends JsonSerializer<TalkIds> {
/**
* Serializes a TalkIds object into the following JSON string:
* Example: { "talk_ids" : [ 5931, 5930 ] }
*/
#Override
public void serialize(TalkIds talkIds, JsonGenerator jsonGenerator,
SerializerProvider provider)
throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeArrayFieldStart(TalkIds.API_DICTIONARY_KEY);
for (Integer talkId : talkIds.getTalkIds()) {
jsonGenerator.writeNumber(talkId);
}
jsonGenerator.writeEndArray();
jsonGenerator.writeEndObject();
}
}
The class is used here:
#JsonSerialize(using = TalkIdsSerializer.class)
public class TalkIds { /* ... */ }
I want test the behavior of the serializer and came up with the following:
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
public class TalkIdsSerializerTest {
protected final ArrayList<Integer> TALK_IDS =
new ArrayList<>(Arrays.asList(5931, 5930));
protected TalkIdsSerializer talkIdsSerializer;
#Before
public void setup() throws IOException {
talkIdsSerializer = new TalkIdsSerializer();
}
#Test
public void testSerialize() throws IOException {
StringWriter stringWriter = new StringWriter();
JsonGenerator jsonGenerator =
new JsonFactory().createGenerator(stringWriter);
TalkIds talkIds = new TalkIds();
talkIds.add(TALK_IDS);
talkIdsSerializer.serialize(talkIds, jsonGenerator, null);
String string = stringWriter.toString(); // string is ""
assertNotNull(string);
assertTrue(string.length() > 0);
stringWriter.close();
}
}
However, nothing is written to the StringWriter. What am I doing wrong?
You need to flush() the generator
Method called to flush any buffered content to the underlying target (output stream, writer), and to flush the target itself as well.
http://fasterxml.github.io/jackson-core/javadoc/2.1.0/com/fasterxml/jackson/core/JsonGenerator.html#flush()
I had a similar requirement, to test a custom serializer. I used objectMapper to get the string directly(since you have already annotated TalkIds with JsonSerialize). You can get the json string from the object as follows
String json = new ObjectMapper().writeValueAsString(talkIds)
For me flush() changed nothing, so I changed the way to test it, in accordance with http://www.baeldung.com/jackson-custom-serialization.
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.StringWriter;
//...
#Test
public void serialize_custom() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(MyCustomSerializer.class, myCustomSerializer);
objectMapper.registerModule(module);
StringWriter stringWriter = new StringWriter();
TalkIds talkIds = new TalkIds();
talkIds.add(TALK_IDS);
objectMapper.writeValue(stringWriter,wi);
assertTrue(stringWriter.toString().length() > 3);
}