blob: f5cb9721db8f60834a9d095b0db4004b22921d9d [file] [log] [blame]
package org.apache.johnzon.jsonb;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.junit.Test;
import jakarta.json.Json;
import jakarta.json.JsonString;
import jakarta.json.bind.Jsonb;
import jakarta.json.bind.JsonbBuilder;
import jakarta.json.bind.JsonbConfig;
import jakarta.json.bind.adapter.JsonbAdapter;
import jakarta.json.bind.annotation.JsonbTypeAdapter;
import jakarta.json.bind.config.PropertyOrderStrategy;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import static java.util.Arrays.asList;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.endsWith;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
public class AdapterTest {
public static class PathAdapter implements JsonbAdapter<Path, JsonString> {
@Override
public JsonString adaptToJson(final Path path) {
return Json.createValue(path.toString());
}
@Override
public Path adaptFromJson(final JsonString jsonString) {
return Paths.get(jsonString.getString());
}
}
public static class PathWrapper {
public Path path;
}
@Test
public void testSerialize() throws Exception {
try (final Jsonb jsonb = JsonbBuilder.create(new JsonbConfig().withAdapters(new PathAdapter()))) {
final PathWrapper wrapper = new PathWrapper();
wrapper.path = Paths.get("/example/file.txt");
if (System.getProperty("os.name").contains("Windows")) {
assertEquals("{\"path\":\"\\\\example\\\\file.txt\"}", jsonb.toJson(wrapper));
assertEquals("\"\\\\example\\\\file.txt\"", jsonb.toJson(wrapper.path));
} else {
assertEquals("{\"path\":\"/example/file.txt\"}", jsonb.toJson(wrapper));
assertEquals("\"/example/file.txt\"", jsonb.toJson(wrapper.path));
}
}
}
@Test
public void testDeserialize() throws Exception {
try (final Jsonb jsonb = JsonbBuilder.create(new JsonbConfig().withAdapters(new PathAdapter()))) {
final Path expected = Paths.get("/example/file.txt");
assertEquals(expected, jsonb.fromJson("{\"path\":\"/example/file.txt\"}", PathWrapper.class).path);
assertEquals(expected, jsonb.fromJson("\"/example/file.txt\"", Path.class));
}
}
@Test
public void adapt() throws Exception {
try (final Jsonb jsonb = JsonbBuilder.create(new JsonbConfig().withAdapters(new BarAdapter()))) {
final Foo foo = new Foo();
foo.bar = new Bar();
foo.bar.value = 1;
foo.dummy = new Dummy();
foo.dummy.value = 2L;
foo.baz = new Baz();
foo.baz.value = "3";
final String toString = jsonb.toJson(foo);
assertThat(toString, startsWith("{"));
assertThat(toString, containsString("\"bar\":\"1\""));
assertThat(toString, containsString("\"dummy\":\"2\""));
assertThat(toString, containsString("\"baz\":\"3\""));
assertThat(toString, endsWith("}"));
assertEquals("{\"bar\":\"1\",\"dummy\":\"2\",\"baz\":\"3\"}".length(), toString.length());
final Foo read = jsonb.fromJson(toString, Foo.class);
assertEquals(foo.bar.value, read.bar.value);
assertEquals(foo.dummy.value, read.dummy.value);
assertEquals(foo.baz.value, read.baz.value);
}
}
@Test
public void adaptValue() throws Exception {
try (final Jsonb jsonb = JsonbBuilder.create()) {
final Baz baz = new Baz();
baz.value = "test";
final String toString = jsonb.toJson(baz);
assertEquals("\"test\"", toString);
}
}
@Test
public void adaptJson() throws Exception {
try (final Jsonb jsonb = JsonbBuilder.create(new JsonbConfig().withAdapters(new Dummy2Adapter()))) {
final Foo2 foo = new Foo2();
foo.dummy = new Dummy2();
foo.dummy.value = 2L;
final String toString = jsonb.toJson(foo);
assertEquals("{\"dummy\":\"2\"}", toString);
final Foo2 read = jsonb.fromJson(toString, Foo2.class);
assertEquals(foo.dummy.value, read.dummy.value);
}
}
@Test
public void notYetPloymorphism() { // we run it since it checked list/item conversion
final Bar bar = new Bar();
bar.value = 11;
final Bar2 bar2 = new Bar2();
bar2.value = 21;
bar2.value2 = 22;
final Polymorphism foo = new Polymorphism();
foo.bars = new ArrayList<>(asList(bar, bar2));
final Jsonb jsonb = JsonbBuilder.create(
new JsonbConfig()
.setProperty("johnzon.readAttributeBeforeWrite", true)
.withPropertyOrderStrategy(PropertyOrderStrategy.LEXICOGRAPHICAL) /* assertEquals() order */);
final String toString = jsonb.toJson(foo);
assertEquals("{\"bars\":[" +
"{\"type\":\"org.apache.johnzon.jsonb.AdapterTest$Bar\",\"value\":{\"value\":11}}," +
"{\"type\":\"org.apache.johnzon.jsonb.AdapterTest$Bar2\",\"value\":{\"value\":21,\"value2\":22}}]}", toString);
final Polymorphism read = jsonb.fromJson(toString, Polymorphism.class);
assertEquals(2, read.bars.size());
assertEquals(11, read.bars.get(0).value);
assertTrue(Bar.class == read.bars.get(0).getClass());
assertEquals(21, read.bars.get(1).value);
assertTrue(Bar2.class == read.bars.get(1).getClass());
assertEquals(22, Bar2.class.cast(read.bars.get(1)).value2);
}
@Test
public void adaptCollectionValue() {
final Jsonb jsonb = JsonbBuilder.create();
Bar bar = new Bar();
bar.value = 42;
BarCollection barCollection = new BarCollection();
barCollection.collection = new ArrayList<Bar>();
barCollection.collection.add(bar);
String barCollectionJson = jsonb.toJson(barCollection);
assertTrue(barCollectionJson.contains("42"));
BarCollection adaptedBarCollection = jsonb.fromJson(barCollectionJson, BarCollection.class);
assertEquals(1, adaptedBarCollection.collection.size());
assertEquals(42, adaptedBarCollection.collection.get(0).value);
Baz baz = new Baz();
baz.value = "42";
BazCollection bazCollection = new BazCollection();
bazCollection.collection = new ArrayList<Baz>();
bazCollection.collection.add(baz);
String bazCollectionJson = jsonb.toJson(bazCollection);
assertTrue(bazCollectionJson.contains("42"));
BazCollection adaptedBazCollection = jsonb.fromJson(bazCollectionJson, BazCollection.class);
assertEquals(1, adaptedBazCollection.collection.size());
assertEquals("42", adaptedBazCollection.collection.get(0).value);
}
public static class BarCollection {
@JsonbTypeAdapter(BarAdapter.class)
public List<Bar> collection;
}
public static class BazCollection {
public List<Baz> collection;
}
public static class Polymorphism {
@JsonbTypeAdapter(PolyBarAdapter.class)
public List<Bar> bars;
}
public static class TypeInstance {
private String type;
private Bar value;
public String getType() {
return type;
}
public void setType(final String type) {
this.type = type;
try {
this.value = Bar.class.cast(Thread.currentThread().getContextClassLoader().loadClass(type).newInstance());
} catch (final InstantiationException | IllegalAccessException | ClassNotFoundException e) {
throw new IllegalArgumentException(e);
}
}
public Bar getValue() {
return value;
}
public void setValue(final Bar value) {
this.value = value;
}
}
public static class Foo2 {
@JsonbTypeAdapter(Dummy2Adapter.class)
public Dummy2 dummy;
}
public static class Foo {
public Bar bar;
@JsonbTypeAdapter(DummyAdapter.class)
public Dummy dummy;
public Baz baz;
}
public static class Bar2 extends Bar {
public int value2;
}
public static class Bar {
public int value;
}
public static class PolyBarAdapter implements JsonbAdapter<Bar, TypeInstance> {
@Override
public Bar adaptFromJson(final TypeInstance obj) throws Exception {
return obj.value;
}
@Override
public TypeInstance adaptToJson(final Bar obj) throws Exception {
final TypeInstance typeInstance = new TypeInstance();
typeInstance.type = obj.getClass().getName();
typeInstance.value = obj;
return typeInstance;
}
}
@JsonbTypeAdapter(BazAdapter.class)
public static class Baz {
public String value;
}
public static class BazAdapter implements JsonbAdapter<Baz, String> {
@Override
public String adaptToJson(Baz obj) throws Exception {
return obj.value;
}
@Override
public Baz adaptFromJson(String obj) throws Exception {
Baz baz = new Baz();
baz.value = obj;
return baz;
}
}
public static class Dummy2 {
public long value;
}
public static class Dummy {
public long value;
}
public static class Dummy2Adapter implements JsonbAdapter<Dummy2, JsonString> {
@Override
public Dummy2 adaptFromJson(final JsonString obj) {
final Dummy2 bar = new Dummy2();
bar.value = Long.parseLong(obj.getString());
return bar;
}
@Override
public JsonString adaptToJson(final Dummy2 obj) {
return Json.createValue(Long.toString(obj.value));
}
}
public static class DummyAdapter implements JsonbAdapter<Dummy, String> {
@Override
public Dummy adaptFromJson(final String obj) throws Exception {
final Dummy bar = new Dummy();
bar.value = Long.parseLong(obj);
return bar;
}
@Override
public String adaptToJson(final Dummy obj) throws Exception {
return Long.toString(obj.value);
}
}
public static class BarAdapter implements JsonbAdapter<Bar, String> {
@Override
public String adaptToJson(final Bar obj) throws Exception {
return Integer.toString(obj.value);
}
@Override
public Bar adaptFromJson(final String obj) throws Exception {
final Bar bar = new Bar();
bar.value = Integer.parseInt(obj);
return bar;
}
}
@Test
public void testAdapterOnEnum() {
Jsonb jsonb = JsonbBuilder.newBuilder().build();
DoorDTO door = new DoorDTO();
door.status = DoorStatus.OPEN;
String jsonS = jsonb.toJson(door);
assertEquals(
"The expected result must be a door with a status open as its enum ordinal",
"{\"status\":0}",
jsonS);
DoorDTO doorDTO = jsonb.fromJson(jsonS, DoorDTO.class);
assertEquals(
"The expected result must be a door with a status open as an enum value",
DoorStatus.OPEN,
doorDTO.status);
}
public static class DoorDTO {
@JsonbTypeAdapter(StatusAdapter.class)
public DoorStatus status;
}
public enum DoorStatus {
OPEN, CLOSE
}
public static class StatusAdapter implements JsonbAdapter<DoorStatus, Integer> {
@Override
public Integer adaptToJson(DoorStatus obj) {
return obj.ordinal();
}
@Override
public DoorStatus adaptFromJson(Integer obj) {
return DoorStatus.values()[obj];
}
}
}