package com.fasterxml.jackson.databind.introspect;
import java.lang.annotation.Annotation;
import java.util.*;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.deser.std.StringDeserializer;
import com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer;
import com.fasterxml.jackson.databind.jsontype.NamedType;
import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder;
import com.fasterxml.jackson.databind.ser.std.StringSerializer;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
// started with [databind#1025] in mind
@SuppressWarnings("serial")
public class IntrospectorPairTest extends BaseMapTest
{
static class Introspector1 extends AnnotationIntrospector {
@Override
public Version version() {
return Version.unknownVersion();
}
@Override
public JsonInclude.Value findPropertyInclusion(Annotated a) {
return JsonInclude.Value.empty()
.withContentInclusion(JsonInclude.Include.ALWAYS)
.withValueInclusion(JsonInclude.Include.NON_ABSENT);
}
}
static class Introspector2 extends AnnotationIntrospector {
@Override
public Version version() {
return Version.unknownVersion();
}
@Override
public JsonInclude.Value findPropertyInclusion(Annotated a) {
return JsonInclude.Value.empty()
.withContentInclusion(JsonInclude.Include.NON_EMPTY)
.withValueInclusion(JsonInclude.Include.USE_DEFAULTS);
}
}
static class IntrospectorWithHandlers extends AnnotationIntrospector {
final Object _deserializer;
final Object _serializer;
public IntrospectorWithHandlers(Object deser, Object ser) {
_deserializer = deser;
_serializer = ser;
}
@Override
public Version version() {
return Version.unknownVersion();
}
@Override
public Object findDeserializer(Annotated am) {
return _deserializer;
}
@Override
public Object findSerializer(Annotated am) {
return _serializer;
}
}
static class IntrospectorWithMap extends AnnotationIntrospector
{
private final Map<String, Object> values = new HashMap<>();
private Version version = Version.unknownVersion();
public IntrospectorWithMap add(String key, Object value) {
values.put(key, value);
return this;
}
public IntrospectorWithMap version(Version v) {
version = v;
return this;
}
@Override
public Version version() {
return version;
}
@Override
public JsonInclude.Value findPropertyInclusion(Annotated a) {
return JsonInclude.Value.empty()
.withContentInclusion(JsonInclude.Include.NON_EMPTY)
.withValueInclusion(JsonInclude.Include.USE_DEFAULTS);
}
@Override
public boolean isAnnotationBundle(Annotation ann) {
return _boolean("isAnnotationBundle");
}
/*
/******************************************************
/* General class annotations
/******************************************************
*/
@Override
public PropertyName findRootName(AnnotatedClass ac) {
return (PropertyName) values.get("findRootName");
}
@Override
public JsonIgnoreProperties.Value findPropertyIgnorals(Annotated a) {
return (JsonIgnoreProperties.Value) values.get("findPropertyIgnorals");
}
@Override
public Boolean isIgnorableType(AnnotatedClass ac) {
return (Boolean) values.get("isIgnorableType");
}
@Override
public Object findFilterId(Annotated ann) {
return (Object) values.get("findFilterId");
}
@Override
public Object findNamingStrategy(AnnotatedClass ac) {
return (Object) values.get("findNamingStrategy");
}
@Override
public String findClassDescription(AnnotatedClass ac) {
return (String) values.get("findClassDescription");
}
/*
/******************************************************
/* Property auto-detection
/******************************************************
*/
@Override
public VisibilityChecker<?> findAutoDetectVisibility(AnnotatedClass ac,
VisibilityChecker<?> checker)
{
VisibilityChecker<?> vc = (VisibilityChecker<?>) values.get("findAutoDetectVisibility");
// not really good but:
return (vc == null) ? checker : vc;
}
/*
/******************************************************
/* Type handling
/******************************************************
*/
@Override
public TypeResolverBuilder<?> findTypeResolver(MapperConfig<?> config,
AnnotatedClass ac, JavaType baseType)
{
return (TypeResolverBuilder<?>) values.get("findTypeResolver");
}
@Override
public TypeResolverBuilder<?> findPropertyTypeResolver(MapperConfig<?> config,
AnnotatedMember am, JavaType baseType)
{
return (TypeResolverBuilder<?>) values.get("findPropertyTypeResolver");
}
@Override
public TypeResolverBuilder<?> findPropertyContentTypeResolver(MapperConfig<?> config,
AnnotatedMember am, JavaType baseType)
{
return (TypeResolverBuilder<?>) values.get("findPropertyContentTypeResolver");
}
@SuppressWarnings("unchecked")
@Override
public List<NamedType> findSubtypes(Annotated a)
{
return (List<NamedType>) values.get("findSubtypes");
}
@Override
public String findTypeName(AnnotatedClass ac) {
return (String) values.get("findTypeName");
}
/*
/******************************************************
/* Helper methods
/******************************************************
*/
private boolean _boolean(String key) {
Object ob = values.get(key);
return Boolean.TRUE.equals(ob);
}
}
/*
/**********************************************************
/* Test methods, misc
/**********************************************************
*/
private final IntrospectorWithMap NO_ANNOTATIONS = new IntrospectorWithMap();
public void testVersion() throws Exception
{
Version v = new Version(1, 2, 3, null,
"com.fasterxml", "IntrospectorPairTest");
IntrospectorWithMap withVersion = new IntrospectorWithMap()
.version(v);
assertEquals(v,
new AnnotationIntrospectorPair(withVersion, NO_ANNOTATIONS).version());
assertEquals(Version.unknownVersion(),
new AnnotationIntrospectorPair(NO_ANNOTATIONS, withVersion).version());
}
public void testAccess() throws Exception
{
IntrospectorWithMap intr1 = new IntrospectorWithMap();
AnnotationIntrospectorPair pair = new AnnotationIntrospectorPair(intr1,
NO_ANNOTATIONS);
Collection<AnnotationIntrospector> intrs = pair.allIntrospectors();
assertEquals(2, intrs.size());
Iterator<AnnotationIntrospector> it = intrs.iterator();
assertSame(intr1, it.next());
assertSame(NO_ANNOTATIONS, it.next());
}
public void testAnnotationBundle() throws Exception
{
IntrospectorWithMap isBundle = new IntrospectorWithMap()
.add("isAnnotationBundle", true);
assertTrue(new AnnotationIntrospectorPair(NO_ANNOTATIONS, isBundle)
.isAnnotationBundle(null));
assertTrue(new AnnotationIntrospectorPair(isBundle, NO_ANNOTATIONS)
.isAnnotationBundle(null));
assertFalse(new AnnotationIntrospectorPair(NO_ANNOTATIONS, NO_ANNOTATIONS)
.isAnnotationBundle(null));
}
/*
/**********************************************************
/* Test methods, general class annotations
/**********************************************************
*/
public void testFindRootName() throws Exception
{
PropertyName name = new PropertyName("test");
IntrospectorWithMap intr = new IntrospectorWithMap()
.add("findRootName", name);
assertNull(new AnnotationIntrospectorPair(NO_ANNOTATIONS, NO_ANNOTATIONS).findRootName(null));
assertEquals(name, new AnnotationIntrospectorPair(NO_ANNOTATIONS, intr).findRootName(null));
assertEquals(name, new AnnotationIntrospectorPair(intr, NO_ANNOTATIONS).findRootName(null));
}
public void testPropertyIgnorals() throws Exception
{
JsonIgnoreProperties.Value incl = JsonIgnoreProperties.Value.forIgnoredProperties("foo");
IntrospectorWithMap intr = new IntrospectorWithMap()
.add("findPropertyIgnorals", incl);
IntrospectorWithMap intrEmpty = new IntrospectorWithMap()
.add("findPropertyIgnorals", JsonIgnoreProperties.Value.empty());
assertEquals(JsonIgnoreProperties.Value.empty(),
new AnnotationIntrospectorPair(intrEmpty, intrEmpty).findPropertyIgnorals(null));
// should actually verify inclusion combining, but there are separate tests for that
assertEquals(incl, new AnnotationIntrospectorPair(intrEmpty, intr).findPropertyIgnorals(null));
assertEquals(incl, new AnnotationIntrospectorPair(intr, intrEmpty).findPropertyIgnorals(null));
}
public void testIsIgnorableType() throws Exception
{
IntrospectorWithMap intr1 = new IntrospectorWithMap()
.add("isIgnorableType", Boolean.TRUE);
IntrospectorWithMap intr2 = new IntrospectorWithMap()
.add("isIgnorableType", Boolean.FALSE);
assertNull(new AnnotationIntrospectorPair(NO_ANNOTATIONS, NO_ANNOTATIONS).isIgnorableType(null));
assertEquals(Boolean.TRUE, new AnnotationIntrospectorPair(intr1, intr2).isIgnorableType(null));
assertEquals(Boolean.FALSE, new AnnotationIntrospectorPair(intr2, intr1).isIgnorableType(null));
}
public void testFindFilterId() throws Exception
{
IntrospectorWithMap intr1 = new IntrospectorWithMap()
.add("findFilterId", "a");
IntrospectorWithMap intr2 = new IntrospectorWithMap()
.add("findFilterId", "b");
assertNull(new AnnotationIntrospectorPair(NO_ANNOTATIONS, NO_ANNOTATIONS).findFilterId(null));
assertEquals("a", new AnnotationIntrospectorPair(intr1, intr2).findFilterId(null));
assertEquals("b", new AnnotationIntrospectorPair(intr2, intr1).findFilterId(null));
}
public void testFindNamingStrategy() throws Exception
{
// shouldn't be bogus Classes for real use, but works here
IntrospectorWithMap intr1 = new IntrospectorWithMap()
.add("findNamingStrategy", Integer.class);
IntrospectorWithMap intr2 = new IntrospectorWithMap()
.add("findNamingStrategy", String.class);
assertNull(new AnnotationIntrospectorPair(NO_ANNOTATIONS, NO_ANNOTATIONS).findNamingStrategy(null));
assertEquals(Integer.class,
new AnnotationIntrospectorPair(intr1, intr2).findNamingStrategy(null));
assertEquals(String.class,
new AnnotationIntrospectorPair(intr2, intr1).findNamingStrategy(null));
}
public void testFindClassDescription() throws Exception
{
IntrospectorWithMap intr1 = new IntrospectorWithMap()
.add("findClassDescription", "Desc1");
IntrospectorWithMap intr2 = new IntrospectorWithMap()
.add("findClassDescription", "Desc2");
assertNull(new AnnotationIntrospectorPair(NO_ANNOTATIONS, NO_ANNOTATIONS).findClassDescription(null));
assertEquals("Desc1",
new AnnotationIntrospectorPair(intr1, intr2).findClassDescription(null));
assertEquals("Desc2",
new AnnotationIntrospectorPair(intr2, intr1).findClassDescription(null));
}
// // // 3 deprecated methods, skip
/*
/**********************************************************
/* Test methods, ser/deser
/**********************************************************
*/
public void testFindSerializer() throws Exception
{
final JsonSerializer<?> serString = new StringSerializer();
final JsonSerializer<?> serToString = ToStringSerializer.instance;
AnnotationIntrospector intr1 = new IntrospectorWithHandlers(null, serString);
AnnotationIntrospector intr2 = new IntrospectorWithHandlers(null, serToString);
AnnotationIntrospector nop = AnnotationIntrospector.nopInstance();
AnnotationIntrospector nop2 = new IntrospectorWithHandlers(null, JsonSerializer.None.class);
assertSame(serString,
new AnnotationIntrospectorPair(intr1, intr2).findSerializer(null));
assertSame(serToString,
new AnnotationIntrospectorPair(intr2, intr1).findSerializer(null));
// also: no-op instance should not block real one, regardless
assertSame(serString,
new AnnotationIntrospectorPair(nop, intr1).findSerializer(null));
assertSame(serString,
new AnnotationIntrospectorPair(nop2, intr1).findSerializer(null));
// nor should no-op result in non-null result
assertNull(new AnnotationIntrospectorPair(nop, nop2).findSerializer(null));
assertNull(new AnnotationIntrospectorPair(nop2, nop).findSerializer(null));
}
public void testFindDeserializer() throws Exception
{
final JsonDeserializer<?> deserString = StringDeserializer.instance;
final JsonDeserializer<?> deserObject = UntypedObjectDeserializer.Vanilla.std;
AnnotationIntrospector intr1 = new IntrospectorWithHandlers(deserString, null);
AnnotationIntrospector intr2 = new IntrospectorWithHandlers(deserObject, null);
AnnotationIntrospector nop = AnnotationIntrospector.nopInstance();
AnnotationIntrospector nop2 = new IntrospectorWithHandlers(JsonDeserializer.None.class, null);
assertSame(deserString,
new AnnotationIntrospectorPair(intr1, intr2).findDeserializer(null));
assertSame(deserObject,
new AnnotationIntrospectorPair(intr2, intr1).findDeserializer(null));
// also: no-op instance should not block real one, regardless
assertSame(deserString,
new AnnotationIntrospectorPair(nop, intr1).findDeserializer(null));
assertSame(deserString,
new AnnotationIntrospectorPair(nop2, intr1).findDeserializer(null));
// nor should no-op result in non-null result
assertNull(new AnnotationIntrospectorPair(nop, nop2).findDeserializer(null));
assertNull(new AnnotationIntrospectorPair(nop2, nop).findDeserializer(null));
}
/*
/******************************************************
/* Property auto-detection
/******************************************************
*/
public void testFindAutoDetectVisibility() throws Exception
{
VisibilityChecker<?> vc = VisibilityChecker.Std.defaultInstance();
IntrospectorWithMap intr1 = new IntrospectorWithMap()
.add("findAutoDetectVisibility", vc);
assertNull(new AnnotationIntrospectorPair(NO_ANNOTATIONS, NO_ANNOTATIONS)
.findAutoDetectVisibility(null, null));
assertSame(vc, new AnnotationIntrospectorPair(intr1, NO_ANNOTATIONS)
.findAutoDetectVisibility(null, null));
assertSame(vc, new AnnotationIntrospectorPair(NO_ANNOTATIONS, intr1)
.findAutoDetectVisibility(null, null));
}
/*
/******************************************************
/* Type handling
/******************************************************
*/
public void testFindTypeResolver() throws Exception
{
/*
TypeResolverBuilder<?> findTypeResolver(MapperConfig<?> config,
AnnotatedClass ac, JavaType baseType)
return (TypeResolverBuilder<?>) values.get("findTypeResolver");
*/
}
public void testFindPropertyTypeResolver() {
}
public void testFindPropertyContentTypeResolver() {
}
public void testFindSubtypes() {
}
public void testFindTypeName() {
IntrospectorWithMap intr1 = new IntrospectorWithMap()
.add("findTypeName", "type1");
IntrospectorWithMap intr2 = new IntrospectorWithMap()
.add("findTypeName", "type2");
assertNull(new AnnotationIntrospectorPair(NO_ANNOTATIONS, NO_ANNOTATIONS).findTypeName(null));
assertEquals("type1",
new AnnotationIntrospectorPair(intr1, intr2).findTypeName(null));
assertEquals("type2",
new AnnotationIntrospectorPair(intr2, intr1).findTypeName(null));
}
/*
/**********************************************************
/* Test methods, others
/**********************************************************
*/
private final AnnotationIntrospectorPair introPair12
= new AnnotationIntrospectorPair(new Introspector1(), new Introspector2());
private final AnnotationIntrospectorPair introPair21
= new AnnotationIntrospectorPair(new Introspector2(), new Introspector1());
// for [databind#1025]
public void testInclusionMerging() throws Exception
{
// argument is ignored by test introspectors, may be null
JsonInclude.Value v12 = introPair12.findPropertyInclusion(null);
JsonInclude.Value v21 = introPair21.findPropertyInclusion(null);
assertEquals(JsonInclude.Include.ALWAYS, v12.getContentInclusion());
assertEquals(JsonInclude.Include.NON_ABSENT, v12.getValueInclusion());
assertEquals(JsonInclude.Include.NON_EMPTY, v21.getContentInclusion());
assertEquals(JsonInclude.Include.NON_ABSENT, v21.getValueInclusion());
}
}