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); + } }