Skip to content

Commit

Permalink
Jackson views/ignored properties: fix view names, in-line custom sche…
Browse files Browse the repository at this point in the history
…mas (#2063)

Signed-off-by: Michael Edgar <[email protected]>
  • Loading branch information
MikeEdgar authored Nov 11, 2024
1 parent 1d86923 commit 458fb2f
Show file tree
Hide file tree
Showing 19 changed files with 487 additions and 123 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiFunction;
Expand Down Expand Up @@ -65,6 +66,9 @@ public Map<String, T> readMap(Collection<AnnotationInstance> annotations,

protected Map<String, T> readMap(Collection<AnnotationInstance> annotations,
Function<AnnotationInstance, Optional<String>> nameFn, BiFunction<String, AnnotationInstance, T> reader) {
if (annotations.isEmpty()) {
return new LinkedHashMap<>(0);
}
IoLogging.logger.annotationsMap('@' + annotationName.local());
return annotations.stream()
.map(annotation -> nameFn.apply(annotation).map(name -> entry(name, reader.apply(name, annotation))))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ public DiscriminatorIO(IOContext<V, A, O, AB, OB> context) {
*/
@Override
public Discriminator read(AnnotationInstance annotation) {
IoLogging.logger.singleAnnotationAs("@Schema", "Discriminator");
String propertyName = value(annotation, SchemaConstant.PROP_DISCRIMINATOR_PROPERTY);
AnnotationInstance[] mapping = value(annotation, SchemaConstant.PROP_DISCRIMINATOR_MAPPING);

if (propertyName == null && mapping == null) {
return null;
}

IoLogging.logger.singleAnnotationAs("@Schema", "Discriminator");
Discriminator discriminator = OASFactory.createDiscriminator();

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ public List<Server> readList(AnnotationInstance[] annotations) {
}

public List<Server> readList(Collection<AnnotationInstance> annotations) {
if (annotations.isEmpty()) {
return new ArrayList<>(0);
}
IoLogging.logger.annotationsArray("@Server");
return annotations.stream()
.map(this::read)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public class SchemaRegistry {
*
* @param type
* the {@link Type} the {@link Schema} applies to
* @param views types applied to the currently-active JsonView (Jackson annotation)
* @param resolver
* a {@link TypeResolver} that will be used to resolve
* parameterized and wildcard types
Expand All @@ -73,7 +74,7 @@ public class SchemaRegistry {
* @return the same schema if not eligible for registration, or a reference
* to the schema registered for the given Type
*/
public Schema checkRegistration(Type type, Set<Type> views, TypeResolver resolver, Schema schema) {
public Schema checkRegistration(Type type, Map<Type, Boolean> views, TypeResolver resolver, Schema schema) {
return register(type, views, resolver, schema, (reg, key) -> reg.register(key, schema, null));
}

Expand All @@ -99,6 +100,7 @@ public Schema checkRegistration(Type type, Set<Type> views, TypeResolver resolve
*
* @param type
* the {@link Type} the {@link Schema} applies to
* @param views types applied to the currently-active JsonView (Jackson annotation)
* @param resolver
* a {@link TypeResolver} that will be used to resolve
* parameterized and wildcard types
Expand All @@ -107,11 +109,11 @@ public Schema checkRegistration(Type type, Set<Type> views, TypeResolver resolve
* @return the same schema if not eligible for registration, or a reference
* to the schema registered for the given Type
*/
public Schema registerReference(Type type, Set<Type> views, TypeResolver resolver, Schema schema) {
public Schema registerReference(Type type, Map<Type, Boolean> views, TypeResolver resolver, Schema schema) {
return register(type, views, resolver, schema, SchemaRegistry::registerReference);
}

public Schema register(Type type, Set<Type> views, TypeResolver resolver, Schema schema,
public Schema register(Type type, Map<Type, Boolean> views, TypeResolver resolver, Schema schema,
BiFunction<SchemaRegistry, TypeKey, Schema> registrationAction) {

final Type resolvedType = TypeResolver.resolve(type, resolver);
Expand All @@ -130,7 +132,7 @@ public Schema register(Type type, Set<Type> views, TypeResolver resolver, Schema
return schema;
}

TypeKey key = new TypeKey(resolvedType, views);
TypeKey key = keyFor(resolvedType, views);

if (hasRef(key)) {
schema = lookupRef(key);
Expand All @@ -153,7 +155,7 @@ public Schema register(Type type, Set<Type> views, TypeResolver resolver, Schema
* @param resolver resolver for type parameter
* @return true when schema references are enabled and the type is present in the registry, otherwise false
*/
public boolean hasSchema(Type type, Set<Type> views, TypeResolver resolver) {
public boolean hasSchema(Type type, Map<Type, Boolean> views, TypeResolver resolver) {
if (disabled) {
return false;
}
Expand Down Expand Up @@ -235,11 +237,20 @@ public SchemaRegistry(AnnotationScannerContext context) {
return;
}

this.register(new TypeKey(type, Collections.emptySet()), schema, Extensions.getName(schema));
this.register(keyFor(type, Collections.emptyMap()), schema, Extensions.getName(schema));
ScannerLogging.logger.configSchemaRegistered(typeSignature);
});
}

private static TypeKey keyFor(Type type, Map<Type, Boolean> views) {
if (TypeUtil.knownJavaType(type.name())) {
// do not apply views for JDK types
return new TypeKey(type, Collections.emptyMap());
}

return new TypeKey(type, views);
}

/**
* Register the provided {@link Schema} for the provided {@link Type}. If an
* existing schema has already been registered for the type, it will be
Expand All @@ -253,8 +264,8 @@ public SchemaRegistry(AnnotationScannerContext context) {
* {@link Schema} to add to the registry
* @return a reference to the newly registered {@link Schema}
*/
public Schema register(Type entityType, Set<Type> views, Schema schema) {
TypeKey key = new TypeKey(entityType, views);
public Schema register(Type entityType, Map<Type, Boolean> views, Schema schema) {
TypeKey key = keyFor(entityType, views);

if (hasRef(key)) {
// This is a replacement registration
Expand Down Expand Up @@ -324,20 +335,20 @@ String deriveName(TypeKey key, String schemaName) {
return name;
}

public Schema lookupRef(Type instanceType, Set<Type> views) {
return lookupRef(new TypeKey(instanceType, views));
public Schema lookupRef(Type instanceType, Map<Type, Boolean> views) {
return lookupRef(keyFor(instanceType, views));
}

public boolean hasRef(Type instanceType, Set<Type> views) {
return hasRef(new TypeKey(instanceType, views));
public boolean hasRef(Type instanceType, Map<Type, Boolean> views) {
return hasRef(keyFor(instanceType, views));
}

public Schema lookupSchema(Type instanceType, Set<Type> views) {
return lookupSchema(new TypeKey(instanceType, views));
public Schema lookupSchema(Type instanceType, Map<Type, Boolean> views) {
return lookupSchema(keyFor(instanceType, views));
}

public boolean hasSchema(Type instanceType, Set<Type> views) {
return hasSchema(new TypeKey(instanceType, views));
public boolean hasSchema(Type instanceType, Map<Type, Boolean> views) {
return hasSchema(keyFor(instanceType, views));
}

public boolean isTypeRegistrationSupported(Type type, Schema schema) {
Expand Down Expand Up @@ -398,20 +409,14 @@ private void remove(TypeKey key) {
*/
public static final class TypeKey {
private final Type type;
private final Set<Type> views;
private final Map<Type, Boolean> views;
private int hashCode = 0;

TypeKey(Type type, Set<Type> views) {
TypeKey(Type type, Map<Type, Boolean> views) {
this.type = type;
this.views = new LinkedHashSet<>(views);
this.views = new LinkedHashMap<>(views);
}

/*
* TypeKey(Type type) {
* this(type, Collections.emptySet());
* }
*/

public String defaultName() {
StringBuilder name = new StringBuilder(type.name().local());

Expand All @@ -436,9 +441,12 @@ public String viewSuffix() {

StringBuilder suffix = new StringBuilder();

for (Type view : views) {
suffix.append('_');
suffix.append(view.name().local());
for (Map.Entry<Type, Boolean> view : views.entrySet()) {
if (Boolean.TRUE.equals(view.getValue())) {
// Only views that are directly specified contribute to the schema's name
suffix.append('_');
suffix.append(view.getKey().name().local());
}
}

return suffix.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ Schema processField() {
// The registeredTypeSchema will be a reference to typeSchema if registration occurs
registrationType = TypeUtil.isWrappedType(entityType) ? fieldType : entityType;
registrationCandidate = !JandexUtil.isRef(schemaAnnotation) &&
typeProcessor.allowRegistration() &&
schemaRegistry.register(registrationType, context.getJsonViews(), typeResolver,
initTypeSchema,
(reg, key) -> null) != initTypeSchema;
Expand Down
Loading

0 comments on commit 458fb2f

Please sign in to comment.