Skip to content

More follow-up work wrt #4907 #5173

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 55 additions & 29 deletions src/main/java/tools/jackson/databind/BeanDescription.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;

import tools.jackson.databind.cfg.MapperConfig;
import tools.jackson.databind.introspect.*;
import tools.jackson.databind.util.Annotations;

Expand Down Expand Up @@ -34,8 +35,8 @@ protected BeanDescription(JavaType type) {
_type = type;
}

public BeanDescription.Supplier supplier() {
return new EagerSupplier(this);
public BeanDescription.Supplier supplier(MapperConfig<?> config) {
return new EagerSupplier(config, this);
}

/*
Expand Down Expand Up @@ -226,12 +227,6 @@ public AnnotatedMember findJsonKeyAccessor() {
*/
public abstract JsonInclude.Value findPropertyInclusion(JsonInclude.Value defValue);

/**
* Method for checking what is the expected format for POJO, as
* defined by possible annotations and possible per-type config overrides.
*/
public abstract JsonFormat.Value findExpectedFormat(Class<?> baseType);

/*
/**********************************************************************
/* Basic API, other
Expand Down Expand Up @@ -280,21 +275,23 @@ public interface Supplier extends java.util.function.Supplier<BeanDescription>
JavaType getType();

boolean isRecordType();

JsonFormat.Value findExpectedFormat(Class<?> baseType);
}

/**
* Partial implementation for lazily-constructed suppliers for {@link BeanDescription} instances.
*/
public static abstract class LazySupplier implements Supplier
protected static abstract class SupplierBase implements Supplier
{
protected final MapperConfig<?> _config;
protected final JavaType _type;

protected transient AnnotatedClass _classDesc;
/**
* Format definitions lazily introspected from class annotations
*/
protected transient JsonFormat.Value _classFormat;

protected transient BeanDescription _beanDesc;

protected LazySupplier(JavaType type) {
_type = type;
protected SupplierBase(MapperConfig<?> config, JavaType type) {
_config = config;
_type = type;
}

// // Simple accessors:
Expand All @@ -308,6 +305,41 @@ protected LazySupplier(JavaType type) {
@Override
public boolean isRecordType() { return _type.isRecordType(); }

// // // Introspection

@Override
public JsonFormat.Value findExpectedFormat(Class<?> baseType)
{
JsonFormat.Value v0 = _classFormat;
if (v0 == null) { // copied from above
v0 = _config.getAnnotationIntrospector().findFormat(_config,
getClassInfo());
if (v0 == null) {
v0 = JsonFormat.Value.empty();
}
_classFormat = v0;
}
JsonFormat.Value v1 = _config.getDefaultPropertyFormat(baseType);
if (v1 == null) {
return v0;
}
return JsonFormat.Value.merge(v0, v1);
}
}

/**
* Partial implementation for lazily-constructed suppliers for {@link BeanDescription} instances.
*/
public static abstract class LazySupplier extends SupplierBase
{
protected transient AnnotatedClass _classDesc;

protected transient BeanDescription _beanDesc;

protected LazySupplier(MapperConfig<?> config, JavaType type) {
super(config, type);
}

// // Entity accessors:

@Override
Expand All @@ -334,6 +366,8 @@ public BeanDescription get() {
return _beanDesc;
}

// // // Internal factory methods

protected abstract AnnotatedClass _introspect(JavaType forType);

protected abstract BeanDescription _construct(JavaType forType, AnnotatedClass ac);
Expand All @@ -343,23 +377,15 @@ public BeanDescription get() {
* Simple {@link Supplier} implementation that just returns pre-constructed
* {@link BeanDescription} instance.
*/
public static class EagerSupplier implements Supplier
public static class EagerSupplier extends SupplierBase
{
protected final BeanDescription _beanDesc;

public EagerSupplier(BeanDescription beanDesc) {
_beanDesc = Objects.requireNonNull(beanDesc);
public EagerSupplier(MapperConfig<?> config, BeanDescription beanDesc) {
super(config, beanDesc.getType());
_beanDesc = beanDesc;
}

@Override
public Class<?> getBeanClass() { return _beanDesc.getBeanClass(); }

@Override
public boolean isRecordType() { return getType().isRecordType(); }

@Override
public JavaType getType() { return _beanDesc.getType(); }

@Override
public BeanDescription get() { return _beanDesc; }

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/tools/jackson/databind/DatabindContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ public abstract BeanDescription introspectBeanDescription(JavaType type,
AnnotatedClass classDef);

public BeanDescription.Supplier lazyIntrospectBeanDescription(JavaType type) {
return new BeanDescription.LazySupplier(type) {
return new BeanDescription.LazySupplier(getConfig(), type) {
@Override
protected BeanDescription _construct(JavaType forType, AnnotatedClass ac) {
// System.out.println("lazyIntrospectBeanDescription.beanDesc("+forType+")");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ public BeanDescription introspectBeanDescriptionForCreation(JavaType type, Annot
}

public BeanDescription.Supplier lazyIntrospectBeanDescriptionForCreation(JavaType type) {
return new BeanDescription.LazySupplier(type) {
return new BeanDescription.LazySupplier(getConfig(), type) {
@Override
protected BeanDescription _construct(JavaType forType, AnnotatedClass ac) {
return introspectBeanDescriptionForCreation(forType, ac);
Expand All @@ -558,7 +558,7 @@ public BeanDescription introspectBeanDescriptionForBuilder(JavaType builderType,

public BeanDescription.Supplier lazyIntrospectBeanDescriptionForBuilder(final JavaType builderType,
final BeanDescription valueTypeDesc) {
return new BeanDescription.LazySupplier(builderType) {
return new BeanDescription.LazySupplier(getConfig(), builderType) {
@Override
protected BeanDescription _construct(JavaType forType, AnnotatedClass ac) {
return introspectBeanDescriptionForBuilder(forType, valueTypeDesc);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ public class BeanDeserializerBuilder
/**********************************************************************
*/

public BeanDeserializerBuilder(BeanDescription.Supplier beanDescRef,
DeserializationContext ctxt)
public BeanDeserializerBuilder(DeserializationContext ctxt,
BeanDescription.Supplier beanDescRef)
{
_beanDescRef = beanDescRef;
_context = ctxt;
Expand Down Expand Up @@ -584,7 +584,7 @@ protected BeanPropertyMap _constructPropMap(Collection<SettableBeanProperty> pro
{
// 07-May-2020, tatu: First find combination of per-type config overrides (higher
// precedence) and per-type annotations (lower):
JsonFormat.Value format = _beanDescRef.get().findExpectedFormat(null);
JsonFormat.Value format = _beanDescRef.findExpectedFormat(null);
// and see if any of those has explicit definition; if not, use global baseline default
Boolean B = format.getFeature(JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES);
boolean caseInsensitive = (B == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ public ValueDeserializer<Object> buildThrowableDeserializer(DeserializationConte
*/
protected BeanDeserializerBuilder constructBeanDeserializerBuilder(DeserializationContext ctxt,
BeanDescription.Supplier beanDescRef) {
return new BeanDeserializerBuilder(beanDescRef, ctxt);
return new BeanDeserializerBuilder(ctxt, beanDescRef);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,11 +378,11 @@ protected ValueDeserializer<?> _createDeserializer2(DeserializationContext ctxt,
}
if (type.isMapLikeType()) {
// 11-Mar-2017, tatu: As per [databind#1554], also need to block
// handling as Map if overriden with "as POJO" option.
// handling as Map if overridden with "as POJO" option.
// Ideally we'd determine it bit later on (to allow custom handler checks)
// but that won't work for other reasons. So do it here.
// (read: rewrite for 3.0)
JsonFormat.Value format = beanDescRef.get().findExpectedFormat(type.getRawClass());
JsonFormat.Value format = beanDescRef.findExpectedFormat(type.getRawClass());
if (format.getShape() != JsonFormat.Shape.POJO) {
MapLikeType mlt = (MapLikeType) type;
if (mlt instanceof MapType) {
Expand All @@ -392,11 +392,10 @@ protected ValueDeserializer<?> _createDeserializer2(DeserializationContext ctxt,
}
}
if (type.isCollectionLikeType()) {
/* One exception is if shape is to be Shape.POJO (or, as alias, OBJECT).
* Ideally we'd determine it bit later on (to allow custom handler checks),
* but that won't work for other reasons. So do it here.
*/
JsonFormat.Value format = beanDescRef.get().findExpectedFormat(type.getRawClass());
// One exception is if shape is to be Shape.POJO (or, as alias, OBJECT).
// Ideally we'd determine it bit later on (to allow custom handler checks),
// but that won't work for other reasons. So do it here.
JsonFormat.Value format = beanDescRef.findExpectedFormat(type.getRawClass());
if (format.getShape() != JsonFormat.Shape.POJO) {
CollectionLikeType clt = (CollectionLikeType) type;
if (clt instanceof CollectionType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ protected BeanDeserializerBase(BeanDeserializerBuilder builder,
;

// Any transformation we may need to apply?
_serializationShape = beanDescRef.get().findExpectedFormat(_beanType.getRawClass()).getShape();
_serializationShape = beanDescRef.findExpectedFormat(_beanType.getRawClass()).getShape();

_needViewProcesing = hasViews;
_vanillaProcessing = !_nonStandardCreation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,28 +371,6 @@ public AnnotatedMethod findMethod(String name, Class<?>[] paramTypes) {
/**********************************************************************
*/

@Override
public JsonFormat.Value findExpectedFormat(Class<?> baseType)
{
JsonFormat.Value v0 = _classFormat;
if (v0 == null) { // copied from above
// 18-Apr-2018, tatu: Bit unclean but apparently `_config` is `null` for
// a small set of pre-discovered simple types that `BasicClassIntrospector`
// may expose. If so, nothing we can do
v0 = (_config == null) ? null
: _intr.findFormat(_config, _classInfo);
if (v0 == null) {
v0 = JsonFormat.Value.empty();
}
_classFormat = v0;
}
JsonFormat.Value v1 = _config.getDefaultPropertyFormat(baseType);
if (v1 == null) {
return v0;
}
return JsonFormat.Value.merge(v0, v1);
}

@Override
public Class<?>[] findDefaultViews()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,7 @@
import tools.jackson.databind.annotation.JsonSerialize;
import tools.jackson.databind.cfg.SerializerFactoryConfig;
import tools.jackson.databind.ext.OptionalHandlerFactory;
import tools.jackson.databind.ext.jdk8.DoubleStreamSerializer;
import tools.jackson.databind.ext.jdk8.IntStreamSerializer;
import tools.jackson.databind.ext.jdk8.Jdk8OptionalSerializer;
import tools.jackson.databind.ext.jdk8.Jdk8StreamSerializer;
import tools.jackson.databind.ext.jdk8.LongStreamSerializer;
import tools.jackson.databind.ext.jdk8.OptionalDoubleSerializer;
import tools.jackson.databind.ext.jdk8.OptionalIntSerializer;
import tools.jackson.databind.ext.jdk8.OptionalLongSerializer;
import tools.jackson.databind.ext.jdk8.*;
import tools.jackson.databind.introspect.*;
import tools.jackson.databind.jsontype.TypeSerializer;
import tools.jackson.databind.ser.jackson.JacksonSerializableSerializer;
Expand Down Expand Up @@ -319,7 +312,8 @@ protected final ValueSerializer<?> findSerializerByPrimaryType(SerializationCont
}

if (type.isTypeOrSubTypeOf(Number.class)) {
JsonFormat.Value format = _calculateEffectiveFormat(beanDescRef, Number.class, formatOverrides);
JsonFormat.Value format = _calculateEffectiveFormat(ctxt,
beanDescRef, Number.class, formatOverrides);

// 21-May-2014, tatu: Couple of alternatives actually
switch (format.getShape()) {
Expand All @@ -338,7 +332,7 @@ protected final ValueSerializer<?> findSerializerByPrimaryType(SerializationCont
JavaType kt = mapEntryType.containedTypeOrUnknown(0);
JavaType vt = mapEntryType.containedTypeOrUnknown(1);
return buildMapEntrySerializer(ctxt, type, beanDescRef,
_calculateEffectiveFormat(beanDescRef, Map.Entry.class, formatOverrides),
_calculateEffectiveFormat(ctxt, beanDescRef, Map.Entry.class, formatOverrides),
staticTyping, kt, vt);
}
if (ByteBuffer.class.isAssignableFrom(raw)) {
Expand Down Expand Up @@ -580,7 +574,8 @@ protected ValueSerializer<?> buildCollectionSerializer(SerializationContext ctxt
}
}

JsonFormat.Value format = _calculateEffectiveFormat(beanDescRef, Collection.class, formatOverrides);
JsonFormat.Value format = _calculateEffectiveFormat(ctxt,
beanDescRef, Collection.class, formatOverrides);
if (ser == null) {
ser = findSerializerByAnnotations(ctxt, type, beanDescRef); // (2) Annotations
if (ser == null) {
Expand Down Expand Up @@ -672,7 +667,8 @@ protected ValueSerializer<?> buildMapSerializer(SerializationContext ctxt,
boolean staticTyping, ValueSerializer<Object> keySerializer,
TypeSerializer elementTypeSerializer, ValueSerializer<Object> elementValueSerializer)
{
JsonFormat.Value format = _calculateEffectiveFormat(beanDescRef, Map.class, formatOverrides);
JsonFormat.Value format = _calculateEffectiveFormat(ctxt,
beanDescRef, Map.class, formatOverrides);

// [databind#467]: This is where we could allow serialization "as POJO": But! It's
// nasty to undo, and does not apply on per-property basis. So, hardly optimal
Expand Down Expand Up @@ -1135,10 +1131,11 @@ private void _removeEnumSelfReferences(BeanDescription beanDesc) {
*
* @since 3.0
*/
protected JsonFormat.Value _calculateEffectiveFormat(BeanDescription.Supplier beanDescRef,
protected JsonFormat.Value _calculateEffectiveFormat(SerializationContext ctxt,
BeanDescription.Supplier beanDescRef,
Class<?> baseType, JsonFormat.Value formatOverrides)
{
JsonFormat.Value fromType = beanDescRef.get().findExpectedFormat(baseType);
JsonFormat.Value fromType = beanDescRef.findExpectedFormat(baseType);
if (formatOverrides == null) {
return fromType;
}
Expand Down
Loading