This is an automated email from the ASF dual-hosted git repository. rmannibucau pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/johnzon.git
The following commit(s) were added to refs/heads/master by this push: new ecdc643 JOHNZON-287 JOHNZON-288 JOHNZON-289 add supportPrivateAccess for jsonbcreator in jsonbaccessmode + cleanup CDI property support ecdc643 is described below commit ecdc643014446ef35be2782224f450360d23ed74 Author: Romain Manni-Bucau <rmannibu...@gmail.com> AuthorDate: Wed Oct 9 14:45:57 2019 +0200 JOHNZON-287 JOHNZON-288 JOHNZON-289 add supportPrivateAccess for jsonbcreator in jsonbaccessmode + cleanup CDI property support --- .../org/apache/johnzon/jsonb/JohnzonBuilder.java | 28 ++++++++++++----- .../org/apache/johnzon/jsonb/JsonbAccessMode.java | 36 +++++++++++++++++----- .../johnzon/jsonb/ConstructorVisibilityTest.java | 24 +++++++++++++++ src/site/markdown/index.md | 9 ++++++ 4 files changed, 81 insertions(+), 16 deletions(-) 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 index f5bb7ea..d33f229 100644 --- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java +++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java @@ -141,6 +141,8 @@ public class JohnzonBuilder implements JsonbBuilder { config = new JsonbConfig(); } + final Boolean skipCdi = shouldSkipCdi(); + // todo: global spec toggle to disable all these ones at once? builder.setUseBigDecimalForObjectNumbers( config.getProperty("johnzon.use-big-decimal-for-object").map(this::toBool).orElse(true)); @@ -222,7 +224,7 @@ public class JohnzonBuilder implements JsonbBuilder { } } throw new IllegalArgumentException("Unsupported factory: " + val); - }).orElseGet(this::findFactory); + }).orElseGet(() -> findFactory(skipCdi)); final AccessMode accessMode = config.getProperty("johnzon.accessMode") .map(this::toAccessMode) @@ -235,9 +237,12 @@ public class JohnzonBuilder implements JsonbBuilder { .map(this::toAccessMode) .orElseGet(() -> new FieldAndMethodAccessMode(true, true, false, true)), config.getProperty("johnzon.failOnMissingCreatorValues") - .map(it -> String.class.isInstance(it) ? Boolean.parseBoolean(it.toString()) : Boolean.class.cast(it)) + .map(this::toBool) .orElse(true) /*spec 1.0 requirement*/, - isNillable)); + isNillable, + config.getProperty("johnzon.supportsPrivateAccess") + .map(this::toBool) + .orElse(false))); builder.setAccessMode(accessMode); // user adapters @@ -285,7 +290,9 @@ public class JohnzonBuilder implements JsonbBuilder { } }); - getBeanManager(); // force detection + if (!skipCdi) { + getBeanManager(); // force detection + } final Types types = new Types(); builder.setReadAttributeBeforeWrite( @@ -340,7 +347,7 @@ public class JohnzonBuilder implements JsonbBuilder { }); }); - final boolean useCdi = cdiIntegration != null && cdiIntegration.isCanWrite() && config.getProperty("johnzon.cdi.activated").map(Boolean.class::cast).orElse(Boolean.TRUE); + final boolean useCdi = cdiIntegration != null && cdiIntegration.isCanWrite() && !skipCdi; if (Closeable.class.isInstance(accessMode)) { builder.addCloseable(Closeable.class.cast(accessMode)); } @@ -408,9 +415,8 @@ public class JohnzonBuilder implements JsonbBuilder { return beanManager; } - private JohnzonAdapterFactory findFactory() { - if (getBeanManager() == NO_BM || config.getProperty("johnzon.skip-cdi") - .map(s -> "true".equalsIgnoreCase(String.valueOf(s))).orElse(false)) { + private JohnzonAdapterFactory findFactory(final boolean skipCdi) { + if (skipCdi || getBeanManager() == NO_BM) { return new SimpleJohnzonAdapterFactory(); } try { // don't trigger CDI is not there @@ -420,6 +426,12 @@ public class JohnzonBuilder implements JsonbBuilder { } } + private Boolean shouldSkipCdi() { + return config.getProperty("johnzon.skip-cdi") + .map(s -> "true".equalsIgnoreCase(String.valueOf(s))) + .orElseGet(() -> !config.getProperty("johnzon.cdi.activated").map(Boolean.class::cast).orElse(Boolean.TRUE)); + } + private ClassLoader tccl() { return ofNullable(Thread.currentThread().getContextClassLoader()).orElseGet(ClassLoader::getSystemClassLoader); } 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 index 4d19dff..c778724 100644 --- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java +++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java @@ -146,6 +146,7 @@ public class JsonbAccessMode implements AccessMode, Closeable { private boolean failOnMissingCreatorValues; private final Types types = new Types(); private final boolean globalIsNillable; + private final boolean supportsPrivateAccess; // CHECKSTYLE:OFF public JsonbAccessMode(final PropertyNamingStrategy propertyNamingStrategy, final String orderValue, @@ -155,7 +156,8 @@ public class JsonbAccessMode implements AccessMode, Closeable { final Supplier<JsonParserFactory> parserFactory, final AccessMode delegate, final boolean failOnMissingCreatorValues, - final boolean globalIsNillable) { + final boolean globalIsNillable, + final boolean supportsPrivateAccess) { // CHECKSTYLE:ON this.globalIsNillable = globalIsNillable; this.naming = propertyNamingStrategy; @@ -169,6 +171,7 @@ public class JsonbAccessMode implements AccessMode, Closeable { this.jsonProvider = jsonProvider; this.parserFactory = parserFactory; this.failOnMissingCreatorValues = failOnMissingCreatorValues; + this.supportsPrivateAccess = supportsPrivateAccess; } @Override @@ -182,22 +185,29 @@ public class JsonbAccessMode implements AccessMode, Closeable { Constructor<?> constructor = null; Method factory = null; boolean invalidConstructorForDeserialization = false; - for (final Constructor<?> c : clazz.getConstructors()) { + for (final Constructor<?> c : supportsPrivateAccess ? clazz.getDeclaredConstructors() : clazz.getConstructors()) { if (c.isAnnotationPresent(JsonbCreator.class)) { if (constructor != null) { throw new JsonbException("Only one constructor or method can have @JsonbCreator"); } + if (!c.isAccessible()) { + c.setAccessible(true); + } constructor = c; } } - for (final Method m : clazz.getMethods()) { + for (final Method m : findPotentialFactoryMethods(clazz).collect(toList())) { final int modifiers = m.getModifiers(); - if (Modifier.isPublic(modifiers) && m.isAnnotationPresent(JsonbCreator.class)) { - if (constructor != null || factory != null) { - throw new JsonbException("Only one constructor or method can have @JsonbCreator"); - } - factory = m; + if ((!supportsPrivateAccess && !Modifier.isPublic(modifiers)) || !m.isAnnotationPresent(JsonbCreator.class)) { + continue; } + if (constructor != null || factory != null) { + throw new JsonbException("Only one constructor or method can have @JsonbCreator"); + } + if (!m.isAccessible()) { + m.setAccessible(true); + } + factory = m; } if (constructor == null && factory == null) { invalidConstructorForDeserialization = Stream.of(clazz.getDeclaredConstructors()) @@ -280,6 +290,16 @@ public class JsonbAccessMode implements AccessMode, Closeable { return methodFactory(clazz, finalFactory, factoryValidator, types, params, converters, itemConverters, objectConverters); } + private Stream<Method> findPotentialFactoryMethods(final Class<?> clazz) { + return (!supportsPrivateAccess ? + Stream.of(clazz.getMethods()) : + Stream.concat( + Stream.of(clazz.getDeclaredMethods()), + clazz.getSuperclass() == null || clazz.getSuperclass() == Object.class || clazz.getSuperclass() == clazz ? + Stream.empty() : + findPotentialFactoryMethods(clazz))); + } + private Factory methodFactory(final Class<?> clazz, final Method finalFactory, final Consumer<Object[]> factoryValidator, final Type[] types, final String[] params, final Adapter<?, ?>[] converters, diff --git a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/ConstructorVisibilityTest.java b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/ConstructorVisibilityTest.java index 0b0949c..bb69ad0 100644 --- a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/ConstructorVisibilityTest.java +++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/ConstructorVisibilityTest.java @@ -18,7 +18,14 @@ */ package org.apache.johnzon.jsonb; +import static org.junit.Assert.assertEquals; + +import javax.json.bind.Jsonb; +import javax.json.bind.JsonbBuilder; +import javax.json.bind.JsonbConfig; import javax.json.bind.JsonbException; +import javax.json.bind.annotation.JsonbCreator; +import javax.json.bind.annotation.JsonbProperty; import org.apache.johnzon.jsonb.test.JsonbRule; import org.junit.Rule; @@ -33,6 +40,14 @@ public class ConstructorVisibilityTest { jsonb.fromJson("{}", PackageCons.class); } + @Test + public void instantiablePackageConstructor() throws Exception { + try (final Jsonb jsonb = JsonbBuilder.create(new JsonbConfig() + .setProperty("johnzon.supportsPrivateAccess", "true"))) { + assertEquals("ok", jsonb.fromJson("{\"foo\":\"ok\"}", InstantiablePackageCons.class).value); + } + } + public static class PackageCons { public String value; @@ -40,4 +55,13 @@ public class ConstructorVisibilityTest { // no-op } } + + public static class InstantiablePackageCons { + public String value; + + @JsonbCreator + InstantiablePackageCons(@JsonbProperty("foo") final String foo) { + this.value = foo; + } + } } diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md index 764c722..3f30aaa 100644 --- a/src/site/markdown/index.md +++ b/src/site/markdown/index.md @@ -314,6 +314,15 @@ JsonbConfig specific properties: * johnzon.support-enum-container-deserialization: prevent EnumMap/EnumSet instantiation, true by default. * johnzon.attributeOrder: Comparator instance to sort properties by name. * johnzon.deduplicateObjects: should instances be deduplicated. +* johnzon.supportsPrivateAccess: should private constructors/methods with `@JsonbCreator` be used too. +* johnzon.fail-on-unknown-properties: should unmapped properties fail the mapping. Similar to `jsonb.fail-on-unknown-properties`. +* johnzon.readAttributeBeforeWrite: should collection be read before being written, it enables to have an "append" mode. +* johnzon.autoAdjustBuffer: should internal read buffers be autoadjusted to stay fixed. +* johnzon.serialize-value-filter: enable to set a filter to not serialize some values. +* johnzon.cdi.activated: should cdi support be active. +* johnzon.accessMode: custom access mode, note that it can disable some JSON-B feature (annotations support). +* johnzon.accessModeDelegate: delegate access mode used by JsonbAccessModel. Enables to enrich default access mode. +* johnzon.failOnMissingCreatorValues: should the mapping fail when a `@JsonbCreator` misses some values. TIP: more in JohnzonBuilder class.