You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@johnzon.apache.org by rm...@apache.org on 2015/12/06 18:45:59 UTC
[3/3] incubator-johnzon git commit: JOHNZON-61 bases for jsonb,
still a lot of tests to add but allows to review more efficiently the
early draft
JOHNZON-61 bases for jsonb, still a lot of tests to add but allows to review more efficiently the early draft
Project: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/commit/b65d149a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/tree/b65d149a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/diff/b65d149a
Branch: refs/heads/master
Commit: b65d149a50bcd16ce71f6969ae46d9311fc9ce36
Parents: 6443633
Author: Romain Manni-Bucau <rm...@gmail.com>
Authored: Sun Dec 6 18:46:31 2015 +0100
Committer: Romain Manni-Bucau <rm...@gmail.com>
Committed: Sun Dec 6 18:46:31 2015 +0100
----------------------------------------------------------------------
.../java/org/apache/johnzon/core/HStack.java | 34 +-
johnzon-distribution/pom.xml | 18 +
johnzon-jsonb/pom.xml | 52 +++
.../org/apache/johnzon/jsonb/JohnsonJsonb.java | 211 +++++++++
.../apache/johnzon/jsonb/JohnzonBuilder.java | 178 ++++++++
.../apache/johnzon/jsonb/JohnzonProvider.java | 29 ++
.../apache/johnzon/jsonb/JsonbAccessMode.java | 454 +++++++++++++++++++
.../jsonb/PropertyNamingStrategyFactory.java | 98 ++++
.../johnzon/jsonb/converter/JsonbConverter.java | 51 +++
.../jsonb/converter/JsonbDateConverter.java | 41 ++
.../jsonb/converter/JsonbDateConverterBase.java | 35 ++
.../converter/JsonbLocalDateConverter.java | 39 ++
.../converter/JsonbLocalDateTimeConverter.java | 40 ++
.../JsonbLocaleParserConverterBase.java | 35 ++
.../jsonb/converter/JsonbNumberConverter.java | 77 ++++
.../jsonb/converter/JsonbValueConverter.java | 34 ++
.../converter/JsonbZonedDateTimeConverter.java | 42 ++
.../services/javax.json.bind.spi.JsonbProvider | 1 +
.../johnzon/jsonb/JohnzonProviderTest.java | 37 ++
.../org/apache/johnzon/jsonb/JsonbReadTest.java | 102 +++++
.../apache/johnzon/jsonb/JsonbWriteTest.java | 132 ++++++
.../PropertyNamingStrategyFactoryTest.java | 52 +++
.../java/org/apache/johnzon/mapper/Mapper.java | 30 +-
.../apache/johnzon/mapper/MapperBuilder.java | 42 +-
.../johnzon/mapper/access/AccessMode.java | 13 +
.../johnzon/mapper/access/BaseAccessMode.java | 125 ++++-
.../johnzon/mapper/access/FieldAccessMode.java | 23 +-
.../mapper/access/FieldAndMethodAccessMode.java | 37 +-
.../johnzon/mapper/access/MethodAccessMode.java | 20 +-
.../johnzon/mapper/reflection/Converters.java | 78 ++++
.../johnzon/mapper/reflection/Mappings.java | 215 ++++-----
.../org/apache/johnzon/mapper/MapperTest.java | 2 +-
jsonb-api/pom.xml | 39 ++
.../src/main/java/javax/json/bind/Jsonb.java | 49 ++
.../main/java/javax/json/bind/JsonbBuilder.java | 50 ++
.../main/java/javax/json/bind/JsonbConfig.java | 94 ++++
.../java/javax/json/bind/JsonbException.java | 31 ++
.../javax/json/bind/adapter/JsonbAdapter.java | 52 +++
.../json/bind/annotation/JsonbAnnotation.java | 26 ++
.../json/bind/annotation/JsonbCreator.java | 30 ++
.../json/bind/annotation/JsonbDateFormat.java | 40 ++
.../json/bind/annotation/JsonbNillable.java | 31 ++
.../json/bind/annotation/JsonbNumberFormat.java | 40 ++
.../json/bind/annotation/JsonbProperty.java | 35 ++
.../bind/annotation/JsonbPropertyOrder.java | 31 ++
.../json/bind/annotation/JsonbTransient.java | 32 ++
.../json/bind/annotation/JsonbTypeAdapter.java | 32 ++
.../javax/json/bind/annotation/JsonbValue.java | 32 ++
.../json/bind/annotation/JsonbVisibility.java | 34 ++
.../json/bind/config/BinaryDataStrategy.java | 29 ++
.../bind/config/PropertyNamingStrategy.java | 30 ++
.../json/bind/config/PropertyOrderStrategy.java | 29 ++
.../bind/config/PropertyVisibilityStrategy.java | 27 ++
.../java/javax/json/bind/spi/JsonbProvider.java | 59 +++
pom.xml | 28 +-
55 files changed, 3058 insertions(+), 199 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-core/src/main/java/org/apache/johnzon/core/HStack.java
----------------------------------------------------------------------
diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/HStack.java b/johnzon-core/src/main/java/org/apache/johnzon/core/HStack.java
index 94f07ae..b2d57bd 100644
--- a/johnzon-core/src/main/java/org/apache/johnzon/core/HStack.java
+++ b/johnzon-core/src/main/java/org/apache/johnzon/core/HStack.java
@@ -20,15 +20,15 @@ package org.apache.johnzon.core;
import java.io.Serializable;
-public class HStack<T> implements Serializable{
+public class HStack<T> implements Serializable {
private Node<T> topElement = null;
private int size;
-
-
- private static final class Node<T> implements Serializable{
- final Node<T> previous;
- final T object;
+
+
+ private static final class Node<T> implements Serializable {
+ private final Node<T> previous;
+ private final T object;
private Node(final Node<T> previous, final T object) {
super();
@@ -36,29 +36,31 @@ public class HStack<T> implements Serializable{
this.object = object;
}
}
-
-
+
+
void push(T object) {
topElement = new Node<T>(topElement, object);
size++;
}
-
+
T pop() {
-
- if(topElement == null) { return null; }
-
+
+ if (topElement == null) {
+ return null;
+ }
+
T tmp = topElement.object;
topElement = topElement.previous;
size--;
return tmp;
}
-
+
T peek() {
- return topElement == null?null:topElement.object;
+ return topElement == null ? null : topElement.object;
}
-
+
int size() {
return size;
}
-
+
}
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-distribution/pom.xml
----------------------------------------------------------------------
diff --git a/johnzon-distribution/pom.xml b/johnzon-distribution/pom.xml
index 3f2c10f..7f92fa2 100644
--- a/johnzon-distribution/pom.xml
+++ b/johnzon-distribution/pom.xml
@@ -139,6 +139,24 @@
<version>${project.version}</version>
<classifier>javadoc</classifier>
</dependency>
+
+ <dependency>
+ <groupId>org.apache.johnzon</groupId>
+ <artifactId>johnzon-jsonb</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.johnzon</groupId>
+ <artifactId>johnzon-jsonb</artifactId>
+ <version>${project.version}</version>
+ <classifier>sources</classifier>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.johnzon</groupId>
+ <artifactId>johnzon-jsonb</artifactId>
+ <version>${project.version}</version>
+ <classifier>javadoc</classifier>
+ </dependency>
</dependencies>
<build>
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/pom.xml
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/pom.xml b/johnzon-jsonb/pom.xml
new file mode 100644
index 0000000..8c36b72
--- /dev/null
+++ b/johnzon-jsonb/pom.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<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">
+ <parent>
+ <artifactId>johnzon</artifactId>
+ <groupId>org.apache.johnzon</groupId>
+ <version>0.9.3-incubating-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>johnzon-jsonb</artifactId>
+ <name>Johnzon :: JSON-B Implementation</name>
+
+ <properties>
+ <java-compile.version>1.8</java-compile.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.johnzon</groupId>
+ <artifactId>jsonb-api</artifactId>
+ <version>1.0-early-draft</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.johnzon</groupId>
+ <artifactId>johnzon-mapper</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnsonJsonb.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnsonJsonb.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnsonJsonb.java
new file mode 100644
index 0000000..85f9bd1
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnsonJsonb.java
@@ -0,0 +1,211 @@
+/*
+ * 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.
+ */
+package org.apache.johnzon.jsonb;
+
+import org.apache.johnzon.mapper.Mapper;
+
+import javax.json.bind.Jsonb;
+import javax.json.bind.JsonbException;
+import java.io.Closeable;
+import java.io.Flushable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.Writer;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.nio.CharBuffer;
+import java.util.Collection;
+
+public class JohnsonJsonb implements Jsonb {
+ private final Mapper delegate;
+
+ public JohnsonJsonb(final Mapper build) {
+ this.delegate = build;
+ }
+
+ @Override
+ public <T> T fromJson(final String str, final Class<T> type) throws JsonbException {
+ return delegate.readObject(str, type);
+ }
+
+ @Override
+ public <T> T fromJson(final String str, final Type runtimeType) throws JsonbException {
+ if (isArray(runtimeType)) {
+ return (T) delegate.readArray(new StringReader(str), Class.class.cast(runtimeType).getComponentType());
+ } else if (isCollection(runtimeType)) {
+ return (T) delegate.readCollection(new StringReader(str), ParameterizedType.class.cast(runtimeType));
+ }
+ return delegate.readObject(str, runtimeType);
+ }
+
+ @Override
+ public <T> T fromJson(final Readable readable, final Class<T> type) throws JsonbException {
+ return delegate.readObject(toReader(readable), type);
+ }
+
+ @Override
+ public <T> T fromJson(final Readable readable, final Type runtimeType) throws JsonbException {
+ if (isArray(runtimeType)) {
+ return (T) delegate.readArray(toReader(readable), Class.class.cast(runtimeType).getComponentType());
+ } else if (isCollection(runtimeType)) {
+ return (T) delegate.readCollection(toReader(readable), ParameterizedType.class.cast(runtimeType));
+ }
+ return delegate.readObject(toReader(readable), runtimeType);
+ }
+
+ @Override
+ public <T> T fromJson(final InputStream stream, final Class<T> type) throws JsonbException {
+ return delegate.readObject(stream, type);
+ }
+
+ @Override
+ public <T> T fromJson(final InputStream stream, final Type runtimeType) throws JsonbException {
+ if (isArray(runtimeType)) {
+ return (T) delegate.readArray(stream, Class.class.cast(runtimeType).getComponentType());
+ } else if (isCollection(runtimeType)) {
+ return (T) delegate.readCollection(stream, ParameterizedType.class.cast(runtimeType));
+ }
+ return delegate.readObject(stream, runtimeType);
+ }
+
+ @Override
+ public String toJson(final Object object) throws JsonbException {
+ if (isArray(object.getClass())) {
+ return delegate.writeArrayAsString((Object[]) object);
+ } else if (Collection.class.isInstance(object)) {
+ return delegate.writeArrayAsString(Collection.class.cast(object));
+ }
+ return delegate.writeObjectAsString(object);
+ }
+
+ @Override
+ public String toJson(final Object object, final Type runtimeType) throws JsonbException {
+ if (isArray(runtimeType)) {
+ return delegate.writeArrayAsString((Object[]) object);
+ } else if (isCollection(runtimeType)) {
+ return delegate.writeArrayAsString(Collection.class.cast(object));
+ }
+ return delegate.writeObjectAsString(object);
+ }
+
+ @Override
+ public void toJson(final Object object, final Appendable appendable) throws JsonbException {
+ if (isArray(object.getClass())) {
+ delegate.writeArray((Object[]) object, toWriter(appendable));
+ } else if (Collection.class.isInstance(object)) {
+ delegate.writeArray(Collection.class.cast(object), toWriter(appendable));
+ } else {
+ delegate.writeObject(object, toWriter(appendable));
+ }
+ }
+
+ @Override
+ public void toJson(final Object object, final Type runtimeType, final Appendable appendable) throws JsonbException {
+ if (isArray(runtimeType)) {
+ delegate.writeArray((Object[]) object, toWriter(appendable));
+ } else if (isCollection(runtimeType)) {
+ delegate.writeArray(Collection.class.cast(object), toWriter(appendable));
+ } else {
+ delegate.writeObject(object, toWriter(appendable));
+ }
+ }
+
+ @Override
+ public void toJson(final Object object, final OutputStream stream) throws JsonbException {
+ if (isArray(object.getClass())) {
+ delegate.writeArray((Object[]) object, stream);
+ } else if (Collection.class.isInstance(object)) {
+ delegate.writeArray(Collection.class.cast(object), stream);
+ } else {
+ delegate.writeObject(object, stream);
+ }
+ }
+
+ @Override
+ public void toJson(final Object object, final Type runtimeType, final OutputStream stream) throws JsonbException {
+ if (isArray(runtimeType)) {
+ delegate.writeArray((Object[]) object, stream);
+ } else if (isCollection(runtimeType)) {
+ delegate.writeArray(Collection.class.cast(object), stream);
+ } else {
+ delegate.writeObject(object, stream);
+ }
+ }
+
+ private boolean isArray(final Type runtimeType) {
+ return Class.class.isInstance(runtimeType) && Class.class.cast(runtimeType).isArray();
+ }
+
+ private boolean isCollection(final Type runtimeType) {
+ if (!ParameterizedType.class.isInstance(runtimeType)) {
+ return false;
+ }
+ final Type rawType = ParameterizedType.class.cast(runtimeType).getRawType();
+ return Class.class.isInstance(rawType) && Collection.class.isAssignableFrom(Class.class.cast(rawType));
+ }
+
+ private Writer toWriter(final Appendable appendable) {
+ return Writer.class.isInstance(appendable) ? Writer.class.cast(appendable) :
+ new Writer() {
+ @Override
+ public void write(final char[] cbuf, final int off, final int len) throws IOException {
+ appendable.append(new String(cbuf, off, len));
+ }
+
+ @Override
+ public void flush() throws IOException {
+ if (Flushable.class.isInstance(appendable)) {
+ Flushable.class.cast(appendable);
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (Closeable.class.isInstance(appendable)) {
+ Closeable.class.cast(appendable);
+ }
+ }
+ };
+ }
+
+ private Reader toReader(final Readable readable) {
+ return Reader.class.isInstance(readable) ? Reader.class.cast(readable) :
+ new Reader() {
+ @Override
+ public int read(final char[] cbuf, final int off, final int len) throws IOException {
+ int r;
+ final CharBuffer cb = CharBuffer.allocate(len);
+ while ((r = readable.read(cb)) >= 0) {
+ System.arraycopy(cb.array(), 0, cbuf, off, r);
+ }
+ return readable.read(CharBuffer.allocate(len));
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (Closeable.class.isInstance(readable)) {
+ Closeable.class.cast(readable);
+ }
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
new file mode 100644
index 0000000..9b2c47d
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ */
+package org.apache.johnzon.jsonb;
+
+import org.apache.johnzon.core.AbstractJsonFactory;
+import org.apache.johnzon.core.JsonGeneratorFactoryImpl;
+import org.apache.johnzon.jsonb.converter.JsonbConverter;
+import org.apache.johnzon.mapper.Converter;
+import org.apache.johnzon.mapper.MapperBuilder;
+
+import javax.json.bind.Jsonb;
+import javax.json.bind.JsonbBuilder;
+import javax.json.bind.JsonbConfig;
+import javax.json.bind.adapter.JsonbAdapter;
+import javax.json.bind.annotation.JsonbVisibility;
+import javax.json.bind.config.BinaryDataStrategy;
+import javax.json.bind.config.PropertyNamingStrategy;
+import javax.json.bind.config.PropertyVisibilityStrategy;
+import javax.json.spi.JsonProvider;
+import javax.json.stream.JsonGenerator;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import static java.util.Collections.emptyMap;
+import static java.util.Optional.ofNullable;
+import static javax.json.bind.config.PropertyNamingStrategy.IDENTITY;
+import static javax.json.bind.config.PropertyOrderStrategy.ANY;
+
+public class JohnzonBuilder implements JsonbBuilder {
+ private final MapperBuilder builder = new MapperBuilder();
+ private JsonProvider jsonp;
+ private JsonbConfig config;
+
+ @Override
+ public JsonbBuilder withConfig(final JsonbConfig config) {
+ this.config = config;
+ return this;
+ }
+
+ @Override
+ public JsonbBuilder withProvider(final JsonProvider jsonpProvider) {
+ this.jsonp = jsonpProvider;
+ return this;
+ }
+
+ @Override
+ public Jsonb build() {
+ if (jsonp != null) {
+ builder.setGeneratorFactory(jsonp.createGeneratorFactory(generatorConfig()));
+ builder.setReaderFactory(jsonp.createReaderFactory(emptyMap()));
+ }
+
+ if (config == null) {
+ config = new JsonbConfig();
+ }
+
+ if (config.getProperty(JsonbConfig.FORMATTING).map(Boolean.class::cast).orElse(false)) {
+ builder.setPretty(true);
+ }
+
+ config.getProperty(JsonbConfig.ENCODING).ifPresent(encoding -> builder.setEncoding(String.valueOf(encoding)));
+ config.getProperty(JsonbConfig.NULL_VALUES).ifPresent(serNulls -> builder.setSkipNull(!Boolean.class.cast(serNulls)));
+
+ final Optional<Object> namingStrategyValue = config.getProperty(JsonbConfig.PROPERTY_NAMING_STRATEGY);
+
+ final PropertyNamingStrategy propertyNamingStrategy = new PropertyNamingStrategyFactory(namingStrategyValue.orElse(IDENTITY)).create();
+ final String orderValue = config.getProperty(JsonbConfig.PROPERTY_ORDER_STRATEGY).map(String::valueOf).orElse(ANY);
+ final PropertyVisibilityStrategy visibilityStrategy = config.getProperty(JsonbConfig.PROPERTY_VISIBILITY_STRATEGY)
+ .map(PropertyVisibilityStrategy.class::cast).orElse(new PropertyVisibilityStrategy() {
+ @Override
+ public boolean isVisible(final Field field) {
+ return true;
+ }
+
+ @Override
+ public boolean isVisible(final Method method) {
+ return true;
+ }
+
+ private PropertyVisibilityStrategy visibilityStrategy(final Class<?> type) { // can be cached
+ Package p = type.getPackage();
+ while (p != null) {
+ final JsonbVisibility visibility = p.getAnnotation(JsonbVisibility.class);
+ if (visibility != null) {
+ try {
+ return visibility.value().newInstance();
+ } catch (final InstantiationException | IllegalAccessException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+ final String name = p.getName();
+ final int end = name.lastIndexOf('.');
+ if (end < 0) {
+ break;
+ }
+ p = Package.getPackage(name.substring(0, end));
+ }
+ return this;
+ }
+ });
+
+ builder.setAccessMode(
+ new JsonbAccessMode(propertyNamingStrategy, orderValue, visibilityStrategy, !namingStrategyValue.orElse("").equals(PropertyNamingStrategy.CASE_INSENSITIVE)));
+
+ config.getProperty(JsonbConfig.ADAPTERS).ifPresent(adapters -> Stream.of(JsonbAdapter[].class.cast(adapters)).forEach(adapter ->
+ builder.addConverter(ofNullable(adapter.getRuntimeBoundType()).orElse(adapter.getBoundType()), new JsonbConverter(adapter))
+ ));
+
+ // TODO:
+ // - Converters for setter/getter
+ // - check adapters when type is not String (breaks our Converter API it seems)
+
+ config.getProperty(JsonbConfig.STRICT_IJSON).map(Boolean.class::cast).ifPresent(ijson -> {
+ // no-op: https://tools.ietf.org/html/rfc7493 the only MUST of the spec sould be fine by default
+ });
+
+ config.getProperty(JsonbConfig.BINARY_DATA_STRATEGY).map(String.class::cast).ifPresent(bin -> {
+ switch (bin) {
+ case BinaryDataStrategy.BYTE:
+ // no-op: our default
+ break;
+ case BinaryDataStrategy.BASE_64:
+ builder.setTreatByteArrayAsBase64(true);
+ break;
+ case BinaryDataStrategy.BASE_64_URL: // needs j8
+ builder.addConverter(byte[].class, new Converter<byte[]>() {
+ @Override
+ public String toString(final byte[] instance) {
+ return Base64.getUrlEncoder().encodeToString(instance);
+ }
+
+ @Override
+ public byte[] fromString(final String text) {
+ return Base64.getUrlDecoder().decode(text.getBytes(StandardCharsets.UTF_8));
+ }
+ });
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported binary configuration: " + bin);
+ }
+ });
+
+ return new JohnsonJsonb(builder.build());
+ }
+
+ private Map<String, ?> generatorConfig() {
+ final Map<String, Object> map = new HashMap<>();
+ if (config == null) {
+ return map;
+ }
+ config.getProperty(JsonGeneratorFactoryImpl.GENERATOR_BUFFER_LENGTH).ifPresent(b -> map.put(JsonGeneratorFactoryImpl.GENERATOR_BUFFER_LENGTH, b));
+ config.getProperty(AbstractJsonFactory.BUFFER_STRATEGY).ifPresent(b -> map.put(AbstractJsonFactory.BUFFER_STRATEGY, b));
+ config.getProperty(JsonbConfig.FORMATTING).ifPresent(b -> map.put(JsonGenerator.PRETTY_PRINTING, b));
+ return map;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonProvider.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonProvider.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonProvider.java
new file mode 100644
index 0000000..d21b915
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonProvider.java
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+package org.apache.johnzon.jsonb;
+
+import javax.json.bind.JsonbBuilder;
+import javax.json.bind.spi.JsonbProvider;
+
+public class JohnzonProvider extends JsonbProvider {
+ @Override
+ public JsonbBuilder create() {
+ return new JohnzonBuilder();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
new file mode 100644
index 0000000..0bd3443
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
@@ -0,0 +1,454 @@
+/*
+ * 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.
+ */
+package org.apache.johnzon.jsonb;
+
+import org.apache.johnzon.jsonb.converter.JsonbConverter;
+import org.apache.johnzon.jsonb.converter.JsonbDateConverter;
+import org.apache.johnzon.jsonb.converter.JsonbLocalDateConverter;
+import org.apache.johnzon.jsonb.converter.JsonbLocalDateTimeConverter;
+import org.apache.johnzon.jsonb.converter.JsonbNumberConverter;
+import org.apache.johnzon.jsonb.converter.JsonbValueConverter;
+import org.apache.johnzon.jsonb.converter.JsonbZonedDateTimeConverter;
+import org.apache.johnzon.mapper.Converter;
+import org.apache.johnzon.mapper.access.AccessMode;
+import org.apache.johnzon.mapper.access.FieldAccessMode;
+import org.apache.johnzon.mapper.access.FieldAndMethodAccessMode;
+import org.apache.johnzon.mapper.access.MethodAccessMode;
+
+import javax.json.bind.JsonbException;
+import javax.json.bind.annotation.JsonbAnnotation;
+import javax.json.bind.annotation.JsonbCreator;
+import javax.json.bind.annotation.JsonbDateFormat;
+import javax.json.bind.annotation.JsonbNillable;
+import javax.json.bind.annotation.JsonbNumberFormat;
+import javax.json.bind.annotation.JsonbProperty;
+import javax.json.bind.annotation.JsonbPropertyOrder;
+import javax.json.bind.annotation.JsonbTransient;
+import javax.json.bind.annotation.JsonbTypeAdapter;
+import javax.json.bind.annotation.JsonbValue;
+import javax.json.bind.config.PropertyNamingStrategy;
+import javax.json.bind.config.PropertyOrderStrategy;
+import javax.json.bind.config.PropertyVisibilityStrategy;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Parameter;
+import java.lang.reflect.Type;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.stream.Stream;
+
+import static java.util.Arrays.asList;
+import static org.apache.johnzon.mapper.reflection.Converters.matches;
+
+public class JsonbAccessMode implements AccessMode {
+ private final PropertyNamingStrategy naming;
+ private final String order;
+ private final PropertyVisibilityStrategy visibility;
+ private final FieldAndMethodAccessMode delegate;
+ private final boolean caseSensitive;
+
+ public JsonbAccessMode(final PropertyNamingStrategy propertyNamingStrategy, final String orderValue,
+ final PropertyVisibilityStrategy visibilityStrategy, final boolean caseSensitive) {
+ this.naming = propertyNamingStrategy;
+ this.order = orderValue;
+ this.visibility = visibilityStrategy;
+ this.caseSensitive = caseSensitive;
+ this.delegate = new FieldAndMethodAccessMode(true, false);
+ }
+
+ @Override
+ public Factory findFactory(final Class<?> clazz) {
+ Constructor<?> constructor = null;
+ Method factory = null;
+ for (final Constructor<?> c : clazz.getConstructors()) {
+ if (c.isAnnotationPresent(JsonbCreator.class)) {
+ if (constructor != null) {
+ throw new IllegalArgumentException("Only one constructor or method can have @JsonbCreator");
+ }
+ constructor = c;
+ }
+ }
+ for (final Method m : clazz.getMethods()) {
+ final int modifiers = m.getModifiers();
+ if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers) && m.isAnnotationPresent(JsonbCreator.class)) {
+ if (constructor != null || factory != null) {
+ throw new IllegalArgumentException("Only one constructor or method can have @JsonbCreator");
+ }
+ factory = m;
+ }
+ }
+ final Constructor<?> finalConstructor = constructor;
+ final Method finalFactory = factory;
+ final Type[] types;
+ final String[] params;
+ final Converter<?>[] converters;
+ final Converter<?>[] itemConverters;
+ if (finalConstructor != null || finalFactory != null) {
+ types = finalConstructor != null ? finalConstructor.getGenericParameterTypes() : finalFactory.getGenericParameterTypes();
+ params = new String[types.length];
+ converters = new Converter[types.length];
+ itemConverters = new Converter[types.length];
+ int i = 0;
+ for (final Parameter parameter : (finalConstructor == null ? finalFactory : finalConstructor).getParameters()) {
+ final JsonbProperty property = parameter.getAnnotation(JsonbProperty.class);
+ params[i] = property != null ? property.value() : parameter.getName();
+
+ final JsonbTypeAdapter adapter = parameter.getAnnotation(JsonbTypeAdapter.class);
+ final JsonbDateFormat dateFormat = parameter.getAnnotation(JsonbDateFormat.class);
+ final JsonbNumberFormat numberFormat = parameter.getAnnotation(JsonbNumberFormat.class);
+ final JsonbValue value = parameter.getAnnotation(JsonbValue.class);
+ if (adapter == null && dateFormat == null && numberFormat == null && value == null) {
+ converters[i] = null;
+ itemConverters[i] = null;
+ } else {
+ validateAnnotations(parameter, adapter, dateFormat, numberFormat, value);
+
+ try {
+ final Converter<?> converter = toConverter(parameter.getType(), adapter, dateFormat, numberFormat);
+ if (matches(parameter.getParameterizedType(), converter)) {
+ converters[i] = converter;
+ itemConverters[i] = null;
+ } else {
+ converters[i] = null;
+ itemConverters[i] = converter;
+ }
+ } catch (final InstantiationException | IllegalAccessException e) {
+ throw new IllegalArgumentException(e);
+ }
+
+ }
+ i++;
+ }
+ } else {
+ types = null;
+ params = null;
+ converters = null;
+ itemConverters = null;
+ }
+
+ return constructor == null && factory == null ? delegate.findFactory(clazz) : (
+ constructor != null ?
+ new Factory() {
+ @Override
+ public Object create(final Object[] params) {
+ try {
+ return finalConstructor.newInstance(params);
+ } catch (final InstantiationException | IllegalAccessException e) {
+ throw new IllegalStateException(e);
+ } catch (final InvocationTargetException e) {
+ throw new IllegalStateException(e.getCause());
+ }
+ }
+
+ @Override
+ public Type[] getParameterTypes() {
+ return types;
+ }
+
+ @Override
+ public String[] getParameterNames() {
+ return params;
+ }
+
+ @Override
+ public Converter<?>[] getParameterConverter() {
+ return converters;
+ }
+
+ @Override
+ public Converter<?>[] getParameterItemConverter() {
+ return itemConverters;
+ }
+ } :
+ new Factory() {
+ @Override
+ public Object create(final Object[] params) {
+ try {
+ final Object invoke = finalFactory.invoke(null, params);
+ if (!clazz.isInstance(invoke)) {
+ throw new IllegalArgumentException(invoke + " is not a " + clazz.getName());
+ }
+ return invoke;
+ } catch (final IllegalAccessException e) {
+ throw new IllegalStateException(e);
+ } catch (final InvocationTargetException e) {
+ throw new IllegalStateException(e.getCause());
+ }
+ }
+
+ @Override
+ public Type[] getParameterTypes() {
+ return types;
+ }
+
+ @Override
+ public String[] getParameterNames() {
+ return params;
+ }
+
+ @Override
+ public Converter<?>[] getParameterConverter() {
+ return converters;
+ }
+
+ @Override
+ public Converter<?>[] getParameterItemConverter() {
+ return itemConverters;
+ }
+ });
+ }
+
+ private void validateAnnotations(final Object parameter,
+ final JsonbTypeAdapter adapter, final JsonbDateFormat dateFormat,
+ final JsonbNumberFormat numberFormat, final JsonbValue value) {
+ int notNull = adapter != null ? 1 : 0;
+ notNull += dateFormat != null ? 1 : 0;
+ notNull += numberFormat != null ? 1 : 0;
+ notNull += value != null ? 1 : 0;
+ if (notNull > 1) {
+ throw new IllegalArgumentException("Conflicting @JsonbXXX on " + parameter);
+ }
+ }
+
+ private Converter<?> toConverter(final Type type,
+ final JsonbTypeAdapter adapter, final JsonbDateFormat dateFormat,
+ final JsonbNumberFormat numberFormat) throws InstantiationException, IllegalAccessException {
+ final Converter<?> converter;
+ if (adapter != null) {
+ converter = new JsonbConverter(adapter.value().newInstance());
+ } else if (dateFormat != null) { // TODO: support lists, LocalDate?
+ if (Date.class == type) {
+ converter = new JsonbDateConverter(dateFormat);
+ } else if (LocalDateTime.class == type) {
+ converter = new JsonbLocalDateTimeConverter(dateFormat);
+ } else if (LocalDate.class == type) {
+ converter = new JsonbLocalDateConverter(dateFormat);
+ } else if (ZonedDateTime.class == type) {
+ converter = new JsonbZonedDateTimeConverter(dateFormat);
+ } else {
+ throw new IllegalArgumentException(type + " not a supported date type");
+ }
+ } else if (numberFormat != null) { // TODO: support lists?
+ converter = new JsonbNumberConverter(numberFormat);
+ } else {
+ converter = new JsonbValueConverter();
+ }
+ return converter;
+ }
+
+ @Override
+ public Map<String, Reader> findReaders(final Class<?> clazz) {
+ final Map<String, Reader> readers = delegate.findReaders(clazz);
+
+ final Comparator<String> orderComparator = orderComparator(clazz);
+ final Comparator<String> keyComparator = caseSensitive ?
+ orderComparator :
+ (o1, o2) -> o1.equalsIgnoreCase(o2) ? 0 : orderComparator.compare(o1, o2);
+
+ final Map<String, Reader> result = keyComparator == null ? new HashMap<>() : new TreeMap<>(keyComparator);
+ for (final Map.Entry<String, Reader> entry : readers.entrySet()) {
+ final Reader value = entry.getValue();
+ if (shouldSkip(visibility, value)) {
+ continue;
+ }
+
+ // we are visible
+ final JsonbProperty property = value.getAnnotation(JsonbProperty.class);
+ final JsonbNillable nillable = value.getAnnotation(JsonbNillable.class);
+ final boolean isNillable = nillable != null || (property != null && property.nillable());
+ final JsonbTypeAdapter adapter = value.getAnnotation(JsonbTypeAdapter.class);
+ final JsonbDateFormat dateFormat = value.getAnnotation(JsonbDateFormat.class);
+ final JsonbNumberFormat numberFormat = value.getAnnotation(JsonbNumberFormat.class);
+ final JsonbValue jsonbValue = value.getAnnotation(JsonbValue.class);
+ validateAnnotations(value, adapter, dateFormat, numberFormat, jsonbValue);
+
+ final Converter<?> converter;
+ try {
+ converter = adapter == null && dateFormat == null && numberFormat == null && jsonbValue == null ? null :
+ toConverter(value.getType(), adapter, dateFormat, numberFormat);
+ } catch (final InstantiationException | IllegalAccessException e) {
+ throw new IllegalArgumentException(e);
+ }
+
+ result.put(property == null || property.value().isEmpty() ? naming.translateName(entry.getKey()) : property.value(), new Reader() {
+ @Override
+ public Object read(final Object instance) {
+ return value.read(instance);
+ }
+
+ @Override
+ public Type getType() {
+ return value.getType();
+ }
+
+ @Override
+ public <T extends Annotation> T getAnnotation(final Class<T> clazz) {
+ return value.getAnnotation(clazz);
+ }
+
+ @Override
+ public Converter<?> findConverter() {
+ return converter;
+ }
+
+ @Override
+ public boolean isNillable() {
+ return isNillable;
+ }
+ });
+ }
+ return result;
+ }
+
+ @Override
+ public Map<String, Writer> findWriters(final Class<?> clazz) {
+ final Map<String, Writer> writers = delegate.findWriters(clazz);
+
+ final Comparator<String> keyComparator = orderComparator(clazz);
+ final Map<String, Writer> result = keyComparator == null ? new HashMap<>() : new TreeMap<>(keyComparator);
+ for (final Map.Entry<String, Writer> entry : writers.entrySet()) {
+ final Writer value = entry.getValue();
+ if (shouldSkip(visibility, value)) {
+ continue;
+ }
+
+ // we are visible
+ final JsonbProperty property = value.getAnnotation(JsonbProperty.class);
+ final JsonbNillable nillable = value.getAnnotation(JsonbNillable.class);
+ final boolean isNillable = nillable != null || (property != null && property.nillable());
+ final JsonbTypeAdapter adapter = value.getAnnotation(JsonbTypeAdapter.class);
+ final JsonbDateFormat dateFormat = value.getAnnotation(JsonbDateFormat.class);
+ final JsonbNumberFormat numberFormat = value.getAnnotation(JsonbNumberFormat.class);
+ final JsonbValue jsonbValue = value.getAnnotation(JsonbValue.class);
+ validateAnnotations(value, adapter, dateFormat, numberFormat, jsonbValue);
+
+ final Converter<?> converter;
+ try {
+ converter = adapter == null && dateFormat == null && numberFormat == null && jsonbValue == null ? null :
+ toConverter(value.getType(), adapter, dateFormat, numberFormat);
+ } catch (final InstantiationException | IllegalAccessException e) {
+ throw new IllegalArgumentException(e);
+ }
+
+ result.put(property == null || property.value().isEmpty() ? naming.translateName(entry.getKey()) : property.value(), new Writer() {
+ @Override
+ public void write(final Object instance, final Object val) {
+ value.write(instance, val);
+ }
+
+ @Override
+ public Type getType() {
+ return value.getType();
+ }
+
+ @Override
+ public <T extends Annotation> T getAnnotation(final Class<T> clazz) {
+ return value.getAnnotation(clazz);
+ }
+
+ @Override
+ public Converter<?> findConverter() {
+ return converter;
+ }
+
+ @Override
+ public boolean isNillable() {
+ return isNillable;
+ }
+ });
+ }
+ return result;
+ }
+
+ private boolean isTransient(final DecoratedType dt, final PropertyVisibilityStrategy visibility) {
+ return shouldSkip(visibility, dt) ||
+ (FieldAndMethodAccessMode.CompositeDecoratedType.class.isInstance(dt) &&
+ Stream.of(FieldAndMethodAccessMode.CompositeDecoratedType.class.cast(dt).getType1(), FieldAndMethodAccessMode.CompositeDecoratedType.class.cast(dt).getType2())
+ .map(t -> shouldSkip(visibility, t))
+ .filter(a -> a)
+ .findAny()
+ .isPresent());
+ }
+
+ private boolean shouldSkip(final PropertyVisibilityStrategy visibility, final DecoratedType t) {
+ return t.getAnnotation(JsonbTransient.class) != null ||
+ (FieldAccessMode.FieldDecoratedType.class.isInstance(t) && !visibility.isVisible(FieldAccessMode.FieldDecoratedType.class.cast(t).getField())) ||
+ (MethodAccessMode.MethodDecoratedType.class.isInstance(t) && !visibility.isVisible(MethodAccessMode.MethodDecoratedType.class.cast(t).getMethod()));
+ }
+
+ private boolean checkTransient(final Annotation[] annotations) {
+ boolean hasTransient = false;
+ boolean hasJsonb = false;
+ for (final Annotation a : annotations) {
+ if (a.annotationType() == JsonbTransient.class) {
+ hasTransient = true;
+ } else if (a.annotationType().isAnnotationPresent(JsonbAnnotation.class)) {
+ hasJsonb = true;
+ }
+ }
+ if (hasJsonb && hasTransient) {
+ throw new JsonbException("@JsonbTransient doesnt work with other @JsonbXXX: " + asList(annotations));
+ }
+ return hasTransient;
+ }
+
+ private Comparator<String> orderComparator(final Class<?> clazz) {
+ final Comparator<String> keyComparator;
+ final JsonbPropertyOrder orderAnnotation = clazz.getAnnotation(JsonbPropertyOrder.class);
+ if (orderAnnotation != null) {
+ final List<String> indexed = new ArrayList<>(asList(orderAnnotation.value()));
+ keyComparator = (o1, o2) -> {
+ final int i1 = indexed.indexOf(o1);
+ final int i2 = indexed.indexOf(o2);
+ if (i1 < 0) {
+ return 1;
+ }
+ return i1 - i2;
+ };
+ } else if (order != null) {
+ switch (order) {
+ case PropertyOrderStrategy.ANY:
+ keyComparator = null;
+ break;
+ case PropertyOrderStrategy.LEXICOGRAPHICAL:
+ keyComparator = String::compareTo;
+ break;
+ case PropertyOrderStrategy.REVERSE:
+ keyComparator = (o1, o2) -> o2.compareTo(o1);
+ break;
+ default:
+ keyComparator = null;
+ }
+ } else {
+ keyComparator = null;
+ }
+ return keyComparator;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/PropertyNamingStrategyFactory.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/PropertyNamingStrategyFactory.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/PropertyNamingStrategyFactory.java
new file mode 100644
index 0000000..badfc15
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/PropertyNamingStrategyFactory.java
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+package org.apache.johnzon.jsonb;
+
+import javax.json.bind.config.PropertyNamingStrategy;
+import java.util.function.Function;
+
+public class PropertyNamingStrategyFactory {
+ private final Object value;
+
+ public PropertyNamingStrategyFactory(final Object value) {
+ this.value = value;
+ }
+
+ public PropertyNamingStrategy create() {
+ if (String.class.isInstance(value)) {
+ final String val = value.toString();
+ switch (val) {
+ case PropertyNamingStrategy.IDENTITY:
+ return propertyName -> propertyName;
+ case PropertyNamingStrategy.LOWER_CASE_WITH_DASHES:
+ return new ConfigurableNamingStrategy(Character::toLowerCase, '-');
+ case PropertyNamingStrategy.LOWER_CASE_WITH_UNDERSCORES:
+ return new ConfigurableNamingStrategy(Character::toLowerCase, '_');
+ case PropertyNamingStrategy.UPPER_CAMEL_CASE:
+ return camelCaseStrategy();
+ case PropertyNamingStrategy.UPPER_CAMEL_CASE_WITH_SPACES:
+ final PropertyNamingStrategy camelCase = camelCaseStrategy();
+ final PropertyNamingStrategy space = new ConfigurableNamingStrategy(Function.identity(), ' ');
+ return propertyName -> camelCase.translateName(space.translateName(propertyName));
+ case PropertyNamingStrategy.CASE_INSENSITIVE:
+ return propertyName -> propertyName;
+ default:
+ throw new IllegalArgumentException(val + " unknown as PropertyNamingStrategy");
+ }
+ }
+ if (PropertyNamingStrategy.class.isInstance(value)) {
+ return PropertyNamingStrategy.class.cast(value);
+ }
+ throw new IllegalArgumentException(value + " not supported as PropertyNamingStrategy");
+ }
+
+ private PropertyNamingStrategy camelCaseStrategy() {
+ return propertyName -> Character.toUpperCase(propertyName.charAt(0)) + (propertyName.length() > 1 ? propertyName.substring(1) : "");
+ }
+
+ private static class ConfigurableNamingStrategy implements PropertyNamingStrategy {
+ private final Function<Character, Character> converter;
+ private final char separator;
+
+ public ConfigurableNamingStrategy(final Function<Character, Character> wordConverter, final char sep) {
+ this.converter = wordConverter;
+ this.separator = sep;
+ }
+
+ @Override
+ public String translateName(final String propertyName) {
+ final StringBuilder global = new StringBuilder();
+
+ final StringBuilder current = new StringBuilder();
+ for (int i = 0; i < propertyName.length(); i++) {
+ final char c = propertyName.charAt(i);
+ if (Character.isUpperCase(c)) {
+ final char transformed = converter.apply(c);
+ if (current.length() > 0) {
+ global.append(current).append(separator);
+ current.setLength(0);
+ }
+ current.append(transformed);
+ } else {
+ current.append(c);
+ }
+ }
+ if (current.length() > 0) {
+ global.append(current);
+ } else {
+ global.setLength(global.length() - 1); // remove last sep
+ }
+ return global.toString();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbConverter.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbConverter.java
new file mode 100644
index 0000000..9758d6e
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbConverter.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+package org.apache.johnzon.jsonb.converter;
+
+import org.apache.johnzon.mapper.Converter;
+
+import javax.json.bind.JsonbException;
+import javax.json.bind.adapter.JsonbAdapter;
+
+// TODO
+public class JsonbConverter implements Converter<Object> {
+ private final JsonbAdapter adapter;
+
+ public JsonbConverter(final JsonbAdapter adapter) {
+ this.adapter = adapter;
+ }
+
+ @Override
+ public String toString(final Object instance) {
+ try {
+ return adapter.adaptTo(instance);
+ } catch (final Exception e) {
+ throw new JsonbException(e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public Object fromString(String text) {
+ try {
+ return adapter.adaptFrom(text);
+ } catch (final Exception e) {
+ throw new JsonbException(e.getMessage(), e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbDateConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbDateConverter.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbDateConverter.java
new file mode 100644
index 0000000..813009c
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbDateConverter.java
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+package org.apache.johnzon.jsonb.converter;
+
+import javax.json.bind.annotation.JsonbDateFormat;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.Date;
+
+public class JsonbDateConverter extends JsonbDateConverterBase<Date> {
+ public JsonbDateConverter(final JsonbDateFormat dateFormat) {
+ super(dateFormat);
+ }
+
+ @Override
+ public String toString(final Date instance) {
+ return formatter == null ? Long.toString(instance.getTime()) : formatter.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(instance.getTime()), ZoneOffset.UTC));
+ }
+
+ @Override
+ public Date fromString(final String text) {
+ return formatter == null ? new Date(Long.parseLong(text)) : Date.from(LocalDateTime.parse(text, formatter).toInstant(ZoneOffset.UTC));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbDateConverterBase.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbDateConverterBase.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbDateConverterBase.java
new file mode 100644
index 0000000..8d961c4
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbDateConverterBase.java
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+package org.apache.johnzon.jsonb.converter;
+
+import javax.json.bind.annotation.JsonbDateFormat;
+import java.time.format.DateTimeFormatter;
+
+public abstract class JsonbDateConverterBase<T> extends JsonbLocaleParserConverterBase<T> {
+ protected final DateTimeFormatter formatter;
+
+ protected JsonbDateConverterBase(final JsonbDateFormat dateFormat) {
+ final String value = dateFormat.value();
+ final String locale = dateFormat.locale();
+ final boolean ms = value.equals(JsonbDateFormat.TIME_IN_MILLIS);
+ formatter = ms ? null :
+ (!locale.equals(JsonbDateFormat.DEFAULT_LOCALE) ?
+ DateTimeFormatter.ofPattern(value).withLocale(newLocale(locale)) : DateTimeFormatter.ofPattern(value));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocalDateConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocalDateConverter.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocalDateConverter.java
new file mode 100644
index 0000000..fa8578d
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocalDateConverter.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+package org.apache.johnzon.jsonb.converter;
+
+import javax.json.bind.annotation.JsonbDateFormat;
+import java.time.LocalDate;
+import java.util.concurrent.TimeUnit;
+
+public class JsonbLocalDateConverter extends JsonbDateConverterBase<LocalDate> {
+ public JsonbLocalDateConverter(final JsonbDateFormat dateFormat) {
+ super(dateFormat);
+ }
+
+ @Override
+ public String toString(final LocalDate instance) {
+ return formatter == null ? Long.toString(TimeUnit.DAYS.toMillis(instance.toEpochDay())) : instance.format(formatter);
+ }
+
+ @Override
+ public LocalDate fromString(final String text) {
+ return formatter == null ? LocalDate.ofEpochDay(TimeUnit.MILLISECONDS.toDays(Long.parseLong(text))) : LocalDate.parse(text, formatter);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocalDateTimeConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocalDateTimeConverter.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocalDateTimeConverter.java
new file mode 100644
index 0000000..b0c3018
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocalDateTimeConverter.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+package org.apache.johnzon.jsonb.converter;
+
+import javax.json.bind.annotation.JsonbDateFormat;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+
+public class JsonbLocalDateTimeConverter extends JsonbDateConverterBase<LocalDateTime> {
+ public JsonbLocalDateTimeConverter(final JsonbDateFormat dateFormat) {
+ super(dateFormat);
+ }
+
+ @Override
+ public String toString(final LocalDateTime instance) {
+ return formatter == null ? Long.toString(instance.toInstant(ZoneOffset.UTC).toEpochMilli()) : instance.format(formatter);
+ }
+
+ @Override
+ public LocalDateTime fromString(final String text) {
+ return formatter == null ? LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(text)), ZoneOffset.UTC) : LocalDateTime.parse(text, formatter);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocaleParserConverterBase.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocaleParserConverterBase.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocaleParserConverterBase.java
new file mode 100644
index 0000000..414a7a5
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocaleParserConverterBase.java
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+package org.apache.johnzon.jsonb.converter;
+
+import org.apache.johnzon.mapper.Converter;
+
+import java.util.Locale;
+
+public abstract class JsonbLocaleParserConverterBase<T> implements Converter<T> {
+ protected Locale newLocale(final String locale) {
+ final String[] parts = locale.split("-");
+ switch (parts.length) {
+ case 1: return new Locale(locale);
+ case 2: return new Locale(parts[0], parts[1]);
+ case 3: return new Locale(parts[0], parts[1], parts[2]);
+ default: throw new IllegalArgumentException(locale);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbNumberConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbNumberConverter.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbNumberConverter.java
new file mode 100644
index 0000000..563968e
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbNumberConverter.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+package org.apache.johnzon.jsonb.converter;
+
+import javax.json.bind.annotation.JsonbNumberFormat;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.util.Queue;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+public class JsonbNumberConverter extends JsonbLocaleParserConverterBase<Number> {
+ private final Supplier<NumberFormat> delegateFactory; // NumberFormat is not thread safe
+ private final Queue<NumberFormat> pool = new ArrayBlockingQueue<>(30); // configurable?
+
+ public JsonbNumberConverter(final JsonbNumberFormat numberFormat) {
+ final String locale = numberFormat.locale();
+ final String format = numberFormat.value();
+ final boolean customLocale = !JsonbNumberFormat.DEFAULT_LOCALE.equals(locale);
+ if (format.isEmpty() && customLocale) {
+ delegateFactory = () -> NumberFormat.getInstance(newLocale(locale));
+ } else if (format.isEmpty()) {
+ delegateFactory = NumberFormat::getInstance;
+ } else if (customLocale) {
+ delegateFactory = () -> new DecimalFormat(format, DecimalFormatSymbols.getInstance(newLocale(locale)));
+ } else {
+ delegateFactory = () -> new DecimalFormat(format);
+ }
+ }
+
+ @Override
+ public String toString(final Number instance) {
+ return execute(f -> f.format(instance));
+ }
+
+ @Override
+ public Number fromString(final String text) {
+ return execute(f -> {
+ try {
+ return f.parse(text);
+ } catch (final ParseException e) {
+ throw new IllegalArgumentException(e);
+ }
+ });
+ }
+
+ private <T> T execute(final Function<NumberFormat, T> function) {
+ NumberFormat format = pool.poll();
+ if (format == null) {
+ format = delegateFactory.get();
+ }
+ try {
+ return function.apply(format);
+ } finally {
+ pool.add(format);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbValueConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbValueConverter.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbValueConverter.java
new file mode 100644
index 0000000..a4b6ec3
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbValueConverter.java
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+package org.apache.johnzon.jsonb.converter;
+
+import org.apache.johnzon.mapper.Converter;
+
+// TODO?
+public class JsonbValueConverter implements Converter<Object> {
+ @Override
+ public String toString(final Object instance) {
+ return String.valueOf(instance);
+ }
+
+ @Override
+ public Object fromString(final String text) {
+ return text;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbZonedDateTimeConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbZonedDateTimeConverter.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbZonedDateTimeConverter.java
new file mode 100644
index 0000000..d5ce9fc
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbZonedDateTimeConverter.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+package org.apache.johnzon.jsonb.converter;
+
+import javax.json.bind.annotation.JsonbDateFormat;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+
+public class JsonbZonedDateTimeConverter extends JsonbDateConverterBase<ZonedDateTime> {
+ private static final ZoneId UTC = ZoneId.of("UTC");
+
+ public JsonbZonedDateTimeConverter(final JsonbDateFormat dateFormat) {
+ super(dateFormat);
+ }
+
+ @Override
+ public String toString(final ZonedDateTime instance) {
+ return formatter == null ? Long.toString(instance.toInstant().toEpochMilli()) : instance.format(formatter);
+ }
+
+ @Override
+ public ZonedDateTime fromString(final String text) {
+ return formatter == null ? ZonedDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(text)), UTC) : ZonedDateTime.parse(text, formatter);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/resources/META-INF/services/javax.json.bind.spi.JsonbProvider
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/resources/META-INF/services/javax.json.bind.spi.JsonbProvider b/johnzon-jsonb/src/main/resources/META-INF/services/javax.json.bind.spi.JsonbProvider
new file mode 100644
index 0000000..4edadc5
--- /dev/null
+++ b/johnzon-jsonb/src/main/resources/META-INF/services/javax.json.bind.spi.JsonbProvider
@@ -0,0 +1 @@
+org.apache.johnzon.jsonb.JohnzonProvider
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonProviderTest.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonProviderTest.java b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonProviderTest.java
new file mode 100644
index 0000000..b35bd2d
--- /dev/null
+++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonProviderTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+package org.apache.johnzon.jsonb;
+
+import org.junit.Test;
+
+import javax.json.bind.spi.JsonbProvider;
+
+import static org.junit.Assert.assertNotNull;
+
+public class JohnzonProviderTest {
+ @Test
+ public void provider() {
+ assertNotNull(JsonbProvider.provider());
+ }
+
+ @Test
+ public void create() {
+ assertNotNull(JsonbProvider.provider().create());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbReadTest.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbReadTest.java b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbReadTest.java
new file mode 100644
index 0000000..4b19cff
--- /dev/null
+++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbReadTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+package org.apache.johnzon.jsonb;
+
+import org.junit.Test;
+
+import javax.json.bind.annotation.JsonbDateFormat;
+import javax.json.bind.annotation.JsonbProperty;
+import javax.json.bind.spi.JsonbProvider;
+import java.io.StringReader;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+import static org.junit.Assert.assertEquals;
+
+public class JsonbReadTest {
+ @Test
+ public void simple() {
+ assertEquals("test", JsonbProvider.provider().create().build().fromJson(new StringReader("{\"value\":\"test\"}"), Simple.class).value);
+ }
+
+ @Test
+ public void propertyMapping() {
+ assertEquals("test", JsonbProvider.provider().create().build().fromJson(new StringReader("{\"simple\":\"test\"}"), SimpleProperty.class).value);
+ }
+
+ @Test
+ public void date() { // ok, can fail at midnight, acceptable risk
+ final String date = DateTimeFormatter.ofPattern("d. LLLL yyyy").format(LocalDate.now());
+ assertEquals(
+ LocalDate.now().getYear(),
+ JsonbProvider.provider().create().build().fromJson(new StringReader("{\"date\":\"" + date + "\"}"), DateFormatting.class).date.getYear());
+ }
+
+ public static class Simple {
+ private String value;
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(final String value) {
+ this.value = value;
+ }
+ }
+
+ public static class SimpleProperty {
+ @JsonbProperty("simple")
+ private String value;
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(final String value) {
+ this.value = value;
+ }
+ }
+
+ public static class SimplePropertyNillable {
+ @JsonbProperty(nillable = true)
+ private String value;
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(final String value) {
+ this.value = value;
+ }
+ }
+
+ public static class DateFormatting {
+ @JsonbDateFormat(value = "d. LLLL yyyy")
+ @JsonbProperty(nillable = true)
+ private LocalDate date;
+
+ public LocalDate getDate() {
+ return date;
+ }
+
+ public void setDate(final LocalDate value) {
+ this.date = value;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbWriteTest.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbWriteTest.java b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbWriteTest.java
new file mode 100644
index 0000000..273c7fc
--- /dev/null
+++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbWriteTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+package org.apache.johnzon.jsonb;
+
+import org.junit.Test;
+
+import javax.json.bind.annotation.JsonbDateFormat;
+import javax.json.bind.annotation.JsonbProperty;
+import javax.json.bind.spi.JsonbProvider;
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+
+public class JsonbWriteTest {
+ @Test
+ public void simple() {
+ final Simple simple = new Simple();
+ simple.setValue("test");
+ assertEquals("{\"value\":\"test\"}", JsonbProvider.provider().create().build().toJson(simple));
+ }
+
+ @Test
+ public void propertyMapping() {
+ final SimpleProperty simple = new SimpleProperty();
+ simple.setValue("test");
+ assertEquals("{\"simple\":\"test\"}", JsonbProvider.provider().create().build().toJson(simple));
+ }
+
+ @Test
+ public void map() {
+ final Map<String, String> map = new HashMap<>();
+ map.put("a", "b");
+ assertEquals("{\"a\":\"b\"}", JsonbProvider.provider().create().build().toJson(map));
+ }
+
+ @Test
+ public void list() {
+ final Collection<String> map = asList("a", "b");
+ assertEquals("[\"a\",\"b\"]", JsonbProvider.provider().create().build().toJson(map));
+ }
+
+ @Test
+ public void propertyMappingNotNillable() {
+ final SimpleProperty simple = new SimpleProperty();
+ assertEquals("{}", JsonbProvider.provider().create().build().toJson(simple));
+ }
+
+ @Test
+ public void propertyNillable() {
+ final SimplePropertyNillable simple = new SimplePropertyNillable();
+ assertEquals("{\"value\":null}", JsonbProvider.provider().create().build().toJson(simple));
+ }
+
+ @Test
+ public void date() {
+ final DateFormatting simple = new DateFormatting();
+ simple.setDate(LocalDateTime.now());
+ assertEquals("{\"date\":\"" + LocalDateTime.now().getYear() + "\"}", JsonbProvider.provider().create().build().toJson(simple));
+ }
+
+ public static class Simple {
+ private String value;
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(final String value) {
+ this.value = value;
+ }
+ }
+
+ public static class SimpleProperty {
+ @JsonbProperty("simple")
+ private String value;
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(final String value) {
+ this.value = value;
+ }
+ }
+
+ public static class SimplePropertyNillable {
+ @JsonbProperty(nillable = true)
+ private String value;
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(final String value) {
+ this.value = value;
+ }
+ }
+
+ public static class DateFormatting {
+ @JsonbDateFormat(value = "yyyy")
+ @JsonbProperty(nillable = true)
+ private LocalDateTime date;
+
+ public LocalDateTime getDate() {
+ return date;
+ }
+
+ public void setDate(final LocalDateTime value) {
+ this.date = value;
+ }
+ }
+}