はじめに
2017/7/7にJSON-BがFinal Releaseになったので、もはやJSON-Bでいいんだけど、過去の自分の作業記録ということで。
EclipseLink Moxyを利用してJSONをPOJOにバインドするサンプル。 JAXBを利用するので最初は違和感があったけど、慣れればそれほど気にならない。
ディレクトリ構成
. |-- pom.xml `-- src |-- main | |-- java | | `-- redj | | `-- moxy | | |-- JaxbJson.java | | `-- binding | | |-- Person.java | | `-- Root.java | `-- resources | `-- META-INF | `-- services | `-- javax.xml.bind.JAXBContext `-- test |-- java | `-- redj | `-- moxy | `-- JaxbJsonTest.java `-- resources `-- redj `-- moxy `-- data.json
ソースコード
src/test/resources/redj/moxy/data.json
テストデータとして、以下のJSONを利用。
{ "persons": [ { "first-name": "Ichiro", "last-name": "Yamada", "age": 20 }, { "first-name": "Taro", "last-name": "Suzuki", "age": 30 } ] }
pom.xml
<?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>redj-moxy</groupId> <artifactId>redj-moxy</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <properties> <!-- configurations --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <!-- dependency versions --> <junit.version>4.12</junit.version> <eclipselink.version>2.7.0</eclipselink.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>org.eclipse.persistence.moxy</artifactId> <version>${eclipselink.version}</version> </dependency> </dependencies> </project>
src/main/java/redj/moxy/JaxbJson.java
JSON <=> POJOの変換を行うクラスで、ほぼJAXBのラッパー。 MarshallerとUnmarshallerにEclipseLink固有のプロパティを設定している点がポイント。
package redj.moxy; import java.io.InputStream; import java.io.OutputStream; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.transform.stream.StreamSource; public class JaxbJson { private final JAXBContext jaxbContext; public JaxbJson(Class<?>... classes) throws JAXBException { this.jaxbContext = JAXBContext.newInstance(classes); } public <T> T read(InputStream in, Class<T> clazz) throws JAXBException { Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); unmarshaller.setProperty("eclipselink.json.include-root", false); unmarshaller.setProperty("eclipselink.media-type", "application/json"); JAXBElement<T> jaxbElement = (JAXBElement) unmarshaller.unmarshal(new StreamSource(in), clazz); return jaxbElement.getValue(); } public void write(OutputStream out, Object object) throws JAXBException { Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.setProperty("eclipselink.json.include-root", false); marshaller.setProperty("eclipselink.media-type", "application/json"); marshaller.marshal(object, out); } }
src/main/java/redj/moxy/binding/Root.java
テストデータのJSONのルートにあたるクラス。
package redj.moxy.binding; import java.util.List; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Root { @XmlElement(name = "persons") public List<Person> persons; }
src/main/java/redj/moxy/binding/Person.java
テストデータのJSONの配列personsの各要素にあたるクラス。
package redj.moxy.binding; import javax.xml.bind.annotation.XmlElement; public class Person { @XmlElement(name = "first-name") public String firstName; @XmlElement(name = "last-name") public String lastName; @XmlElement(name = "age") public int age; }
src/main/resources/META-INF/services/javax.xml.bind.JAXBContext
JAXBの実装をEclipseLink Moxyに切り替えるためのファクトリクラスの指定。
org.eclipse.persistence.jaxb.JAXBContextFactory
src/test/java/redj/moxy/JaxbJsonTest.java
data.jsonをPOJOに変換し、そのPOJOをもう一度JSONに変換して標準出力に出力するテスト。 テストの最後で改行を出力しているのは、単にMavenの出力の見た目を整えるため。
package redj.moxy; import java.io.InputStream; import org.junit.Test; import redj.moxy.binding.Root; public class JaxbJsonTest { @Test public void test() throws Exception { try (InputStream in = getClass().getClassLoader().getResourceAsStream("redj/moxy/data.json")) { JaxbJson jaxbJson = new JaxbJson(Root.class); Root root = jaxbJson.read(in, Root.class); jaxbJson.write(System.out, root); System.out.println(); // I want a newline !! } } }
ビルドとテスト
$ mvn clean install (略) ------------------------------------------------------- T E S T S ------------------------------------------------------- Running redj.moxy.JaxbJsonTest {"persons":[{"first-name":"Ichiro","last-name":"Yamada","age":20},{"first-name":"Taro","last-name":"Suzuki","age":30}]} Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.741 sec (略)