From e9049656a82209f168e76f57ee69e901879b90e1 Mon Sep 17 00:00:00 2001 From: Joe Barnett Date: Thu, 6 May 2021 13:03:26 -0700 Subject: [PATCH] Merge findInjectableValues() results in AnnotationIntrospectorPair As many AnnotationIntrospector implementations use default values for useInput, allow the secondary introspector's useInput value to combine with the primary's id to prevent losing the useInput value. Fixes a special case of #962 seen by the GuiceAnnotationInspector in https://github.com/FasterXML/jackson-modules-base/issues/134 --- .../AnnotationIntrospectorPair.java | 6 +- .../introspect/IntrospectorPairTest.java | 95 +++++++++++++++++++ 2 files changed, 100 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotationIntrospectorPair.java b/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotationIntrospectorPair.java index 7800874edd..2037d00c11 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotationIntrospectorPair.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotationIntrospectorPair.java @@ -300,7 +300,11 @@ public NameTransformer findUnwrappingNameTransformer(AnnotatedMember member) { @Override public JacksonInject.Value findInjectableValue(AnnotatedMember m) { JacksonInject.Value r = _primary.findInjectableValue(m); - return (r == null) ? _secondary.findInjectableValue(m) : r; + if (r == null || r.getUseInput() == null) { + JacksonInject.Value secondary = _secondary.findInjectableValue(m); + r = (r == null || secondary == null) ? secondary : r.withUseInput(secondary.getUseInput()); + } + return r; } @Override diff --git a/src/test/java/com/fasterxml/jackson/databind/introspect/IntrospectorPairTest.java b/src/test/java/com/fasterxml/jackson/databind/introspect/IntrospectorPairTest.java index c198e294bf..dc3292f9fb 100644 --- a/src/test/java/com/fasterxml/jackson/databind/introspect/IntrospectorPairTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/introspect/IntrospectorPairTest.java @@ -3,15 +3,20 @@ import java.lang.annotation.Annotation; import java.util.*; +import com.fasterxml.jackson.annotation.JacksonInject; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.OptBoolean; 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.json.JsonMapper; import com.fasterxml.jackson.databind.jsontype.NamedType; import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder; import com.fasterxml.jackson.databind.ser.std.StringSerializer; @@ -601,4 +606,94 @@ public void testInclusionMerging() throws Exception assertEquals(JsonInclude.Include.NON_EMPTY, v21.getContentInclusion()); assertEquals(JsonInclude.Include.NON_ABSENT, v21.getValueInclusion()); } + + /* + /********************************************************** + /* Introspectors and test for [jackson-modules-base#134]/[databind#962] + /********************************************************** + */ + static class TestIntrospector extends NopAnnotationIntrospector { + @Override + public JacksonInject.Value findInjectableValue(AnnotatedMember m) { + if (m.getRawType() == UnreadableBean.class) { + return JacksonInject.Value.forId("jjj"); + } + return null; + } + } + + static class TestInjector extends InjectableValues { + @Override + public Object findInjectableValue(Object valueId, DeserializationContext ctxt, BeanProperty forProperty, Object beanInstance) { + if (valueId == "jjj") { + UnreadableBean bean = new UnreadableBean(); + bean.setValue(1); + return bean; + } + return null; + } + } + + enum SimpleEnum { ONE, TWO } + + static class UnreadableBean { + public SimpleEnum value; + + public void setValue(SimpleEnum value) { + this.value = value; + } + + public void setValue(Integer intValue) { + this.value = SimpleEnum.values()[intValue]; + } + + public SimpleEnum getValue() { + return value; + } + } + + static class ReadableInjectedBean { + public ReadableInjectedBean(@JacksonInject(useInput = OptBoolean.FALSE) UnreadableBean injectBean) { + this.injectBean = injectBean; + } + @JsonProperty + private String foo; + @JsonIgnore + private UnreadableBean injectBean; + } + + static class UnreadableInjectedBean { + public UnreadableInjectedBean(@JacksonInject UnreadableBean injectBean) { + this.injectBean = injectBean; + } + @JsonProperty + private String foo; + @JsonIgnore + private UnreadableBean injectBean; + } + + public void testMergingIntrospectorsForInjection() throws Exception { + AnnotationIntrospector testIntrospector = new TestIntrospector(); + ObjectMapper mapper = new JsonMapper(); + mapper.setInjectableValues(new TestInjector()); + mapper.setAnnotationIntrospectors( + new AnnotationIntrospectorPair(testIntrospector, + mapper.getSerializationConfig().getAnnotationIntrospector()), + new AnnotationIntrospectorPair(testIntrospector, + mapper.getDeserializationConfig().getAnnotationIntrospector()) + ); + ReadableInjectedBean bean = mapper.readValue("{\"foo\": \"bob\"}", ReadableInjectedBean.class); + assertEquals("bob", bean.foo); + assertEquals(SimpleEnum.TWO, bean.injectBean.value); + + boolean successReadingUnreadableInjectedBean; + try { + UnreadableInjectedBean noBean = mapper.readValue("{\"foo\": \"bob\"}", UnreadableInjectedBean.class); + successReadingUnreadableInjectedBean = true; + } catch (JsonMappingException e) { + successReadingUnreadableInjectedBean = false; + assertTrue(e.getMessage().contains("Conflicting setter definitions")); + } + assertFalse(successReadingUnreadableInjectedBean); + } }