How can I serialize a jgrapht simple graph to json?
Asked Answered
L

5

39

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?

Lepidopteran answered 11/9, 2016 at 17:48 Comment(2)
Although this won't solve your problem, I suspect the object you are trying to seralize contains a reference to the AbstractBaseGraph$ArrayListFactory. This factory is not a POJO and the framework you are using can't workout how to convert this to JSON. Either null it out if possible, or exclude it from JSON convertion, or tell the JSON-Jacson framework to exclude it.Drench
I think you'll need to write your own. Jgrapht's root object is not guaranteed to be set of POJOs, and even if it was, you'll need to break cycles with id's pointing across the JSON tree.Unbearable
L
0

You can disable the exception with:

mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
Lavine answered 30/10, 2019 at 10:2 Comment(0)
Q
0

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.

Quade answered 11/4, 2021 at 7:33 Comment(0)
N
0

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());
           }
       }
   }
Nucleoplasm answered 28/9, 2021 at 19:49 Comment(0)
U
0

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"
            }
        ]
    }
}
Unkempt answered 8/9, 2022 at 13:13 Comment(0)
C
0
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);
Cubage answered 8/12, 2022 at 14:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.