This is an automated email from the ASF dual-hosted git repository. jamesbognar pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/juneau.git
commit 3a74fcd50a49526ead445e492ee5553ae4357c6a Author: James Bognar <[email protected]> AuthorDate: Tue May 12 13:22:19 2026 -0400 refactor: extract SPI seams in commons.bean for bean-runtime types (TODO-5 Step 8a) Lays the groundwork for physically relocating BeanMap/BeanMeta/BeanPropertyMeta and friends into commons.bean by extracting the minimum runtime seams those types need from the marshalling layer. - New SPI: org.apache.juneau.commons.bean.BeanSession. Captures the session-aware operations (convertToType, convertToMemberType, toBeanMap) that BeanMap/BeanPropertyMeta need from MarshallingSession. Target-type parameters are typed as Object so commons.bean does not have to import ClassMeta. - MarshallingSession implements BeanSession; new bridge methods dispatch Object-typed targetType into the existing ClassMeta/Class overloads. - BeanConfigContext gains four bean-modeling-relevant boolean settings that previously only lived on MarshallingContext: beanMapPutReturnsOldValue, ignoreInvocationExceptionsOnGetters/Setters, ignoreUnknownNullBeanProperties. Builder, copy() and defaults are wired through. - MarshallingContext.buildBeanConfigContext() now populates the four new settings from its own resolved values. - BeanPropertyMeta now reads those four settings via BeanConfigContext, so the call sites no longer depend on MarshallingContext. - BeanConfigContext_Test extended to exercise the new defaults, builder fluent setters, and copy() preservation. The 8 target types still reference ClassMeta/MarshallingContext for the remaining type-resolution and registry-lookup hot paths; those will be retyped or seam-extracted in Step 8b alongside the physical git mv. Co-authored-by: Cursor <[email protected]> --- .../juneau/commons/bean/BeanConfigContext.java | 91 +++++++++++++++++++++ .../apache/juneau/commons/bean/BeanSession.java | 92 ++++++++++++++++++++++ .../java/org/apache/juneau/BeanPropertyMeta.java | 10 +-- .../java/org/apache/juneau/MarshallingContext.java | 4 + .../java/org/apache/juneau/MarshallingSession.java | 49 +++++++++++- .../commons/bean/BeanConfigContext_Test.java | 20 +++++ 6 files changed, 260 insertions(+), 6 deletions(-) diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanConfigContext.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanConfigContext.java index e9309fa9ee..63ee537c74 100644 --- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanConfigContext.java +++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanConfigContext.java @@ -92,14 +92,18 @@ public final class BeanConfigContext { private final Visibility beanFieldVisibility; private final Visibility beanMethodVisibility; + private final boolean beanMapPutReturnsOldValue; private final boolean beansRequireDefaultConstructor; private final boolean beansRequireSerializable; private final boolean beansRequireSettersForGetters; private final boolean beansRequireSomeProperties; private final boolean findFluentSetters; + private final boolean ignoreInvocationExceptionsOnGetters; + private final boolean ignoreInvocationExceptionsOnSetters; private final boolean ignoreMissingSetters; private final boolean ignoreTransientFields; private final boolean ignoreUnknownBeanProperties; + private final boolean ignoreUnknownNullBeanProperties; private final boolean unsortedProperties; private final boolean useInterfaceProxies; private final boolean useJavaBeanIntrospector; @@ -120,14 +124,18 @@ public final class BeanConfigContext { beanConstructorVisibility = b.beanConstructorVisibility; beanFieldVisibility = b.beanFieldVisibility; beanMethodVisibility = b.beanMethodVisibility; + beanMapPutReturnsOldValue = b.beanMapPutReturnsOldValue; beansRequireDefaultConstructor = b.beansRequireDefaultConstructor; beansRequireSerializable = b.beansRequireSerializable; beansRequireSettersForGetters = b.beansRequireSettersForGetters; beansRequireSomeProperties = b.beansRequireSomeProperties; findFluentSetters = b.findFluentSetters; + ignoreInvocationExceptionsOnGetters = b.ignoreInvocationExceptionsOnGetters; + ignoreInvocationExceptionsOnSetters = b.ignoreInvocationExceptionsOnSetters; ignoreMissingSetters = b.ignoreMissingSetters; ignoreTransientFields = b.ignoreTransientFields; ignoreUnknownBeanProperties = b.ignoreUnknownBeanProperties; + ignoreUnknownNullBeanProperties = b.ignoreUnknownNullBeanProperties; unsortedProperties = b.unsortedProperties; useInterfaceProxies = b.useInterfaceProxies; useJavaBeanIntrospector = b.useJavaBeanIntrospector; @@ -181,6 +189,17 @@ public final class BeanConfigContext { */ public Visibility getBeanMethodVisibility() { return beanMethodVisibility; } + /** + * Returns whether {@code BeanMap.put(String,Object)} returns the previous property value. + * + * <p> + * When <jk>false</jk> (the default), {@code BeanMap.put(...)} always returns <jk>null</jk> for performance reasons — + * the underlying bean's getter is skipped before the setter is invoked. + * + * @return <jk>true</jk> if old values are returned. + */ + public boolean isBeanMapPutReturnsOldValue() { return beanMapPutReturnsOldValue; } + /** * Returns whether classes must have a no-arg constructor to be considered beans. * @@ -216,6 +235,27 @@ public final class BeanConfigContext { */ public boolean isFindFluentSetters() { return findFluentSetters; } + /** + * Returns whether exceptions thrown from bean property getters should be silently swallowed. + * + * <p> + * When <jk>true</jk>, an exception thrown by a getter is treated as a <jk>null</jk> property value rather than + * propagated to the caller. + * + * @return <jk>true</jk> if getter invocation exceptions are ignored. + */ + public boolean isIgnoreInvocationExceptionsOnGetters() { return ignoreInvocationExceptionsOnGetters; } + + /** + * Returns whether exceptions thrown from bean property setters should be silently swallowed. + * + * <p> + * When <jk>true</jk>, an exception thrown by a setter is suppressed rather than propagated to the caller. + * + * @return <jk>true</jk> if setter invocation exceptions are ignored. + */ + public boolean isIgnoreInvocationExceptionsOnSetters() { return ignoreInvocationExceptionsOnSetters; } + /** * Returns whether bean properties without setters should be silently ignored during deserialization. * @@ -237,6 +277,17 @@ public final class BeanConfigContext { */ public boolean isIgnoreUnknownBeanProperties() { return ignoreUnknownBeanProperties; } + /** + * Returns whether attempts to set unknown bean properties to <jk>null</jk> should be silently ignored. + * + * <p> + * When <jk>true</jk> (the default), trying to set an unknown property to <jk>null</jk> is a no-op rather than an + * error. When <jk>false</jk>, the property setter still rejects unknown property names. + * + * @return <jk>true</jk> if unknown null properties are silently ignored. + */ + public boolean isIgnoreUnknownNullBeanProperties() { return ignoreUnknownNullBeanProperties; } + /** * Returns whether properties should preserve their JVM-discovered (non-alphabetical) order. * @@ -350,14 +401,18 @@ public final class BeanConfigContext { private Visibility beanFieldVisibility = Visibility.PUBLIC; private Visibility beanMethodVisibility = Visibility.PUBLIC; + private boolean beanMapPutReturnsOldValue; private boolean beansRequireDefaultConstructor; private boolean beansRequireSerializable; private boolean beansRequireSettersForGetters; private boolean beansRequireSomeProperties = true; private boolean findFluentSetters; + private boolean ignoreInvocationExceptionsOnGetters; + private boolean ignoreInvocationExceptionsOnSetters; private boolean ignoreMissingSetters = true; private boolean ignoreTransientFields = true; private boolean ignoreUnknownBeanProperties; + private boolean ignoreUnknownNullBeanProperties = true; private boolean unsortedProperties; private boolean useInterfaceProxies = true; private boolean useJavaBeanIntrospector; @@ -380,14 +435,18 @@ public final class BeanConfigContext { beanConstructorVisibility = src.beanConstructorVisibility; beanFieldVisibility = src.beanFieldVisibility; beanMethodVisibility = src.beanMethodVisibility; + beanMapPutReturnsOldValue = src.beanMapPutReturnsOldValue; beansRequireDefaultConstructor = src.beansRequireDefaultConstructor; beansRequireSerializable = src.beansRequireSerializable; beansRequireSettersForGetters = src.beansRequireSettersForGetters; beansRequireSomeProperties = src.beansRequireSomeProperties; findFluentSetters = src.findFluentSetters; + ignoreInvocationExceptionsOnGetters = src.ignoreInvocationExceptionsOnGetters; + ignoreInvocationExceptionsOnSetters = src.ignoreInvocationExceptionsOnSetters; ignoreMissingSetters = src.ignoreMissingSetters; ignoreTransientFields = src.ignoreTransientFields; ignoreUnknownBeanProperties = src.ignoreUnknownBeanProperties; + ignoreUnknownNullBeanProperties = src.ignoreUnknownNullBeanProperties; unsortedProperties = src.unsortedProperties; useInterfaceProxies = src.useInterfaceProxies; useJavaBeanIntrospector = src.useJavaBeanIntrospector; @@ -442,6 +501,14 @@ public final class BeanConfigContext { */ public Builder beanMethodVisibility(Visibility value) { beanMethodVisibility = assertArgNotNull("value", value); return this; } + /** + * Toggles whether {@code BeanMap.put(String,Object)} returns the previous value rather than <jk>null</jk>. + * + * @param value The new value. + * @return This object. + */ + public Builder beanMapPutReturnsOldValue(boolean value) { beanMapPutReturnsOldValue = value; return this; } + /** * Toggles the requirement that beans have a no-arg default constructor. * @@ -482,6 +549,22 @@ public final class BeanConfigContext { */ public Builder findFluentSetters(boolean value) { findFluentSetters = value; return this; } + /** + * Toggles silent suppression of exceptions thrown by bean property getters. + * + * @param value The new value. + * @return This object. + */ + public Builder ignoreInvocationExceptionsOnGetters(boolean value) { ignoreInvocationExceptionsOnGetters = value; return this; } + + /** + * Toggles silent suppression of exceptions thrown by bean property setters. + * + * @param value The new value. + * @return This object. + */ + public Builder ignoreInvocationExceptionsOnSetters(boolean value) { ignoreInvocationExceptionsOnSetters = value; return this; } + /** * Toggles silent ignoring of properties without setters during deserialization. * @@ -506,6 +589,14 @@ public final class BeanConfigContext { */ public Builder ignoreUnknownBeanProperties(boolean value) { ignoreUnknownBeanProperties = value; return this; } + /** + * Toggles silent ignoring of attempts to set unknown bean properties to <jk>null</jk>. + * + * @param value The new value. + * @return This object. + */ + public Builder ignoreUnknownNullBeanProperties(boolean value) { ignoreUnknownNullBeanProperties = value; return this; } + /** * Toggles whether properties remain in JVM-discovered (non-alphabetical) order. * diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanSession.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanSession.java new file mode 100644 index 0000000000..8b4b511079 --- /dev/null +++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanSession.java @@ -0,0 +1,92 @@ +/* + * 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.juneau.commons.bean; + +/** + * Minimum runtime surface that the bean-modeling layer needs from a marshalling session. + * + * <p> + * {@code BeanSession} is an SPI seam between the bean-modeling runtime (in {@code commons.bean}) and the + * marshalling stack (in {@code juneau-marshall}). The marshalling layer's {@code MarshallingSession} + * implements this interface so the bean-modeling types (notably {@code BeanMap} and {@code BeanPropertyMeta}) + * can request session-aware operations — type conversion, bean-map wrapping — without referencing any + * marshalling-aware concrete types. + * + * <p> + * On the commons-side construction path ({@code BeanMeta.of(Class, BeanConfigContext)}) the session is + * <jk>null</jk> and these operations are skipped; the bean-modeling code runs in raw-reflection mode. + * + * <h5 class='section'>Method parameter typing:</h5> + * <p> + * The {@code targetType} parameters are typed as {@link Object} because the marshalling layer expresses them + * as {@code ClassMeta<?>} — a marshalling-side type that {@code commons.bean} cannot reference. Callers in + * the bean-modeling layer pass through whatever opaque type-metadata handle they received; the + * {@code MarshallingSession} implementation interprets it as a {@code ClassMeta}. + * + * <h5 class='section'>See Also:</h5><ul> + * <li class='ja'>{@link BeanConfigContext} — bean-modeling configuration counterpart. + * </ul> + */ +public interface BeanSession { + + /** + * Converts the specified value to the specified target type. + * + * <p> + * Implementations apply any registered conversions, swaps, or coercions necessary to produce a value + * compatible with {@code targetType}. On the marshalling-side, this routes through + * {@code MarshallingSession.convertToType(Object, ClassMeta)}. + * + * @param value The value to convert. May be <jk>null</jk>. + * @param targetType + * The target type — typically a marshalling-side {@code ClassMeta<?>} handle passed through from + * a {@code BeanPropertyMeta} or {@code BeanMap}. Must not be <jk>null</jk>. + * @return The converted value. + */ + Object convertToType(Object value, Object targetType); + + /** + * Converts the specified value to the specified target type, instantiating non-static inner classes against + * an outer instance. + * + * @param outer The outer-class instance for non-static inner classes. May be <jk>null</jk>. + * @param value The value to convert. May be <jk>null</jk>. + * @param targetType The target type — typically a marshalling-side {@code ClassMeta<?>}. Must not be <jk>null</jk>. + * @return The converted value. + */ + Object convertToMemberType(Object outer, Object value, Object targetType); + + /** + * Wraps the specified bean in a {@code BeanMap}. + * + * <p> + * Equivalent to {@code MarshallingSession.toBeanMap(Object)} on the marshalling-side. The return type is + * typed as {@link Object} (rather than {@code BeanMap}) because the bean-modeling {@code BeanMap} runtime + * type currently lives in {@code juneau-marshall}; callers in {@code commons.bean} treat the returned value + * opaquely and pass it through to other {@code BeanSession} / bean-modeling APIs that re-narrow it. + * + * <p> + * The signature is generic to allow implementations (notably {@code MarshallingSession}) to satisfy this + * method with their existing covariant {@code <T> BeanMap<T> toBeanMap(T)} declaration without an + * additional bridge method. + * + * @param <T> The bean type. + * @param bean The bean to wrap. Must not be <jk>null</jk>. + * @return A new bean map (typically a {@code BeanMap}) wrapping the supplied bean. + */ + <T> Object toBeanMap(T bean); +} diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java index 735d2ce234..d21237c5a9 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java @@ -1060,7 +1060,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { return invokeGetter(bean, pName); } catch (Exception e) { - if (nn(bc) && bc.isIgnoreInvocationExceptionsOnGetters()) { + if (config.isIgnoreInvocationExceptionsOnGetters()) { if (nn(rawTypeMeta) && rawTypeMeta.isPrimitive()) return rawTypeMeta.getPrimitiveDefault(); return null; @@ -1167,7 +1167,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { var isCollection = rawTypeMeta.isCollection(); if ((! isDyna) && field == null && setter == null && ! (isMap || isCollection)) { - if ((value1 == null && nn(bc) && bc.isIgnoreUnknownNullBeanProperties()) || config.isIgnoreMissingSetters()) + if ((value1 == null && config.isIgnoreUnknownNullBeanProperties()) || config.isIgnoreMissingSetters()) return null; throw bex(beanMeta.getClassInfo(), "Setter or public field not defined on property ''{0}''", name); } @@ -1186,7 +1186,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { }) private Object setPropertyValue(BeanMap<?> m, String pName, Object value1, Object bean, boolean isMap, boolean isCollection, MarshallingSession session) throws ParseException { try { - var r = (bc.isBeanMapPutReturnsOldValue() || isMap || isCollection) && (nn(getter) || nn(field)) ? get(m, pName) : null; + var r = (config.isBeanMapPutReturnsOldValue() || isMap || isCollection) && (nn(getter) || nn(field)) ? get(m, pName) : null; var propertyClass = rawTypeMeta.inner(); var pcInfo = rawTypeMeta; @@ -1331,7 +1331,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { } catch (BeanRuntimeException e) { throw e; } catch (Exception e1) { - if (bc.isIgnoreInvocationExceptionsOnSetters()) { + if (config.isIgnoreInvocationExceptionsOnSetters()) { if (rawTypeMeta.isPrimitive()) return rawTypeMeta.getPrimitiveDefault(); return null; @@ -1423,7 +1423,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { return swapAndFilterProperty(session, o); } catch (Exception e) { - if (nn(bc) && bc.isIgnoreInvocationExceptionsOnGetters()) { + if (config.isIgnoreInvocationExceptionsOnGetters()) { if (nn(rawTypeMeta) && rawTypeMeta.isPrimitive()) return rawTypeMeta.getPrimitiveDefault(); return null; diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/MarshallingContext.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/MarshallingContext.java index cbf369aae2..91073ef242 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/MarshallingContext.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/MarshallingContext.java @@ -3773,14 +3773,18 @@ public class MarshallingContext extends Context implements ConversionFinder { .beanConstructorVisibility(beanConstructorVisibility) .beanFieldVisibility(beanFieldVisibility) .beanMethodVisibility(beanMethodVisibility) + .beanMapPutReturnsOldValue(beanMapPutReturnsOldValue) .beansRequireDefaultConstructor(beansRequireDefaultConstructor) .beansRequireSerializable(beansRequireSerializable) .beansRequireSettersForGetters(beansRequireSettersForGetters) .beansRequireSomeProperties(beansRequireSomeProperties) .findFluentSetters(findFluentSetters) + .ignoreInvocationExceptionsOnGetters(ignoreInvocationExceptionsOnGetters) + .ignoreInvocationExceptionsOnSetters(ignoreInvocationExceptionsOnSetters) .ignoreMissingSetters(ignoreMissingSetters) .ignoreTransientFields(ignoreTransientFields) .ignoreUnknownBeanProperties(ignoreUnknownBeanProperties) + .ignoreUnknownNullBeanProperties(ignoreUnknownNullBeanProperties) .unsortedProperties(unsortedProperties) .useInterfaceProxies(useInterfaceProxies) .useJavaBeanIntrospector(useJavaBeanIntrospector) diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/MarshallingSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/MarshallingSession.java index 15fe991f6d..0b5358bdec 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/MarshallingSession.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/MarshallingSession.java @@ -54,7 +54,7 @@ import org.apache.juneau.commons.bean.*; "java:S115", // Constants use UPPER_snakeCase naming convention "java:S1452" // Wildcard required - ClassMeta<?>, ObjectSwap<?,?>, etc. for bean metadata }) -public class MarshallingSession extends ContextSession implements ConverterSession { +public class MarshallingSession extends ContextSession implements ConverterSession, BeanSession { // Property name constants private static final String PROP_locale = "locale"; @@ -1270,4 +1270,51 @@ public class MarshallingSession extends ContextSession implements ConverterSessi return array; } + //----------------------------------------------------------------------------------------------------------------- + // BeanSession bridge methods — SPI seam to commons.bean. + //----------------------------------------------------------------------------------------------------------------- + + /** + * Bridge implementation of {@link BeanSession#convertToType(Object, Object)} that dispatches to the + * {@link ClassMeta}-typed overload when the supplied {@code targetType} is a {@link ClassMeta}, or to the + * {@link Class}-typed overload when it is a {@link Class}. + * + * <p> + * The bean-modeling layer calls this method through the {@link BeanSession} interface so it can request type + * conversion without referencing the marshalling-side {@link ClassMeta} concrete type. + * + * @param value The value to convert. May be <jk>null</jk>. + * @param targetType A {@link ClassMeta} or {@link Class} describing the target type. Must not be <jk>null</jk>. + * @return The converted value. + * @throws IllegalArgumentException If {@code targetType} is neither a {@link ClassMeta} nor a {@link Class}. + */ + @Override /* BeanSession */ + public final Object convertToType(Object value, Object targetType) { + if (targetType instanceof ClassMeta<?> cm) + return convertToType(value, cm); + if (targetType instanceof Class<?> c) + return convertToType(value, c); + throw illegalArg("Unsupported targetType for convertToType: {0}", targetType == null ? "null" : targetType.getClass().getName()); + } + + /** + * Bridge implementation of {@link BeanSession#convertToMemberType(Object, Object, Object)} that dispatches to the + * {@link ClassMeta}-typed overload when the supplied {@code targetType} is a {@link ClassMeta}, or to the + * {@link Class}-typed overload when it is a {@link Class}. + * + * @param outer The outer-class instance for non-static inner classes. May be <jk>null</jk>. + * @param value The value to convert. May be <jk>null</jk>. + * @param targetType A {@link ClassMeta} or {@link Class} describing the target type. Must not be <jk>null</jk>. + * @return The converted value. + * @throws IllegalArgumentException If {@code targetType} is neither a {@link ClassMeta} nor a {@link Class}. + */ + @Override /* BeanSession */ + public final Object convertToMemberType(Object outer, Object value, Object targetType) { + if (targetType instanceof ClassMeta<?> cm) + return convertToMemberType(outer, value, cm); + if (targetType instanceof Class<?> c) + return convertToMemberType(outer, value, c); + throw illegalArg("Unsupported targetType for convertToMemberType: {0}", targetType == null ? "null" : targetType.getClass().getName()); + } + } \ No newline at end of file diff --git a/juneau-utest/src/test/java/org/apache/juneau/commons/bean/BeanConfigContext_Test.java b/juneau-utest/src/test/java/org/apache/juneau/commons/bean/BeanConfigContext_Test.java index 77e1e3a8bb..27e445953b 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/commons/bean/BeanConfigContext_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/commons/bean/BeanConfigContext_Test.java @@ -44,14 +44,18 @@ class BeanConfigContext_Test extends TestBase { @Test void a02_default_booleanToggles() { var ctx = BeanConfigContext.DEFAULT; + assertFalse(ctx.isBeanMapPutReturnsOldValue()); assertFalse(ctx.isBeansRequireDefaultConstructor()); assertFalse(ctx.isBeansRequireSerializable()); assertFalse(ctx.isBeansRequireSettersForGetters()); assertTrue(ctx.isBeansRequireSomeProperties()); assertFalse(ctx.isFindFluentSetters()); + assertFalse(ctx.isIgnoreInvocationExceptionsOnGetters()); + assertFalse(ctx.isIgnoreInvocationExceptionsOnSetters()); assertTrue(ctx.isIgnoreMissingSetters()); assertTrue(ctx.isIgnoreTransientFields()); assertFalse(ctx.isIgnoreUnknownBeanProperties()); + assertTrue(ctx.isIgnoreUnknownNullBeanProperties()); assertFalse(ctx.isUnsortedProperties()); assertTrue(ctx.isUseInterfaceProxies()); assertFalse(ctx.isUseJavaBeanIntrospector()); @@ -97,26 +101,34 @@ class BeanConfigContext_Test extends TestBase { @Test void b02_builder_booleanToggles() { var ctx = BeanConfigContext.create() + .beanMapPutReturnsOldValue(true) .beansRequireDefaultConstructor(true) .beansRequireSerializable(true) .beansRequireSettersForGetters(true) .beansRequireSomeProperties(false) .findFluentSetters(true) + .ignoreInvocationExceptionsOnGetters(true) + .ignoreInvocationExceptionsOnSetters(true) .ignoreMissingSetters(false) .ignoreTransientFields(false) .ignoreUnknownBeanProperties(true) + .ignoreUnknownNullBeanProperties(false) .unsortedProperties(true) .useInterfaceProxies(false) .useJavaBeanIntrospector(true) .build(); + assertTrue(ctx.isBeanMapPutReturnsOldValue()); assertTrue(ctx.isBeansRequireDefaultConstructor()); assertTrue(ctx.isBeansRequireSerializable()); assertTrue(ctx.isBeansRequireSettersForGetters()); assertFalse(ctx.isBeansRequireSomeProperties()); assertTrue(ctx.isFindFluentSetters()); + assertTrue(ctx.isIgnoreInvocationExceptionsOnGetters()); + assertTrue(ctx.isIgnoreInvocationExceptionsOnSetters()); assertFalse(ctx.isIgnoreMissingSetters()); assertFalse(ctx.isIgnoreTransientFields()); assertTrue(ctx.isIgnoreUnknownBeanProperties()); + assertFalse(ctx.isIgnoreUnknownNullBeanProperties()); assertTrue(ctx.isUnsortedProperties()); assertFalse(ctx.isUseInterfaceProxies()); assertTrue(ctx.isUseJavaBeanIntrospector()); @@ -244,14 +256,18 @@ class BeanConfigContext_Test extends TestBase { .beanConstructorVisibility(Visibility.PRIVATE) .beanFieldVisibility(Visibility.DEFAULT) .beanMethodVisibility(Visibility.PROTECTED) + .beanMapPutReturnsOldValue(true) .beansRequireDefaultConstructor(true) .beansRequireSerializable(true) .beansRequireSettersForGetters(true) .beansRequireSomeProperties(false) .findFluentSetters(true) + .ignoreInvocationExceptionsOnGetters(true) + .ignoreInvocationExceptionsOnSetters(true) .ignoreMissingSetters(false) .ignoreTransientFields(false) .ignoreUnknownBeanProperties(true) + .ignoreUnknownNullBeanProperties(false) .unsortedProperties(true) .useInterfaceProxies(false) .useJavaBeanIntrospector(true) @@ -271,14 +287,18 @@ class BeanConfigContext_Test extends TestBase { assertEquals(src.getBeanConstructorVisibility(), copy.getBeanConstructorVisibility()); assertEquals(src.getBeanFieldVisibility(), copy.getBeanFieldVisibility()); assertEquals(src.getBeanMethodVisibility(), copy.getBeanMethodVisibility()); + assertEquals(src.isBeanMapPutReturnsOldValue(), copy.isBeanMapPutReturnsOldValue()); assertEquals(src.isBeansRequireDefaultConstructor(), copy.isBeansRequireDefaultConstructor()); assertEquals(src.isBeansRequireSerializable(), copy.isBeansRequireSerializable()); assertEquals(src.isBeansRequireSettersForGetters(), copy.isBeansRequireSettersForGetters()); assertEquals(src.isBeansRequireSomeProperties(), copy.isBeansRequireSomeProperties()); assertEquals(src.isFindFluentSetters(), copy.isFindFluentSetters()); + assertEquals(src.isIgnoreInvocationExceptionsOnGetters(), copy.isIgnoreInvocationExceptionsOnGetters()); + assertEquals(src.isIgnoreInvocationExceptionsOnSetters(), copy.isIgnoreInvocationExceptionsOnSetters()); assertEquals(src.isIgnoreMissingSetters(), copy.isIgnoreMissingSetters()); assertEquals(src.isIgnoreTransientFields(), copy.isIgnoreTransientFields()); assertEquals(src.isIgnoreUnknownBeanProperties(), copy.isIgnoreUnknownBeanProperties()); + assertEquals(src.isIgnoreUnknownNullBeanProperties(), copy.isIgnoreUnknownNullBeanProperties()); assertEquals(src.isUnsortedProperties(), copy.isUnsortedProperties()); assertEquals(src.isUseInterfaceProxies(), copy.isUseInterfaceProxies()); assertEquals(src.isUseJavaBeanIntrospector(), copy.isUseJavaBeanIntrospector());
