diff --git a/pom.xml b/pom.xml index 0eca2f42b5..95c8d31a31 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,7 @@ javax.xml.datatype, javax.xml.namespace, javax.xml.parsers com.fasterxml.jackson.core jackson-annotations - 2.5.0 + 2.6.0-SNAPSHOT com.fasterxml.jackson.core diff --git a/release-notes/VERSION b/release-notes/VERSION index ce72b88be8..9b9f2bc324 100644 --- a/release-notes/VERSION +++ b/release-notes/VERSION @@ -6,6 +6,7 @@ Project: jackson-databind 2.6.0 (not yet released) +#95: Allow read-only properties with `@JsonIgnoreProperties(allowGetters=true)` #312: Support Type Id mappings where two ids map to same Class #348: ObjectMapper.valueToTree does not work with @JsonRawValue (reported by Chris P, pimlottc@github) diff --git a/src/main/java/com/fasterxml/jackson/databind/AnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/AnnotationIntrospector.java index cc1f85ca00..c0973f4e07 100644 --- a/src/main/java/com/fasterxml/jackson/databind/AnnotationIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/databind/AnnotationIntrospector.java @@ -223,11 +223,23 @@ public PropertyName findRootName(AnnotatedClass ac) { * List of property names is applied * after other detection mechanisms, to filter out these specific * properties from being serialized and deserialized. + * + * @param forSerialization True if requesting properties to ignore for serialization; + * false if for deserialization + */ + public String[] findPropertiesToIgnore(Annotated ac, boolean forSerialization) { + // !!! Change direction in 2.7 or later + return findPropertiesToIgnore(ac); + } + + /** + * @deprecated Since 2.6, use variant that takes second argument. */ + @Deprecated public String[] findPropertiesToIgnore(Annotated ac) { return null; } - + /** * Method for checking whether an annotation indicates that all unknown properties */ diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java index d70f9fca4e..1ade8b9131 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java @@ -1164,7 +1164,8 @@ public JsonDeserializer createMapDeserializer(DeserializationContext ctxt, if (deser == null) { ValueInstantiator inst = findValueInstantiator(ctxt, beanDesc); MapDeserializer md = new MapDeserializer(type, inst, keyDes, contentDeser, contentTypeDeser); - md.setIgnorableProperties(config.getAnnotationIntrospector().findPropertiesToIgnore(beanDesc.getClassInfo())); + AnnotationIntrospector ai = config.getAnnotationIntrospector(); + md.setIgnorableProperties(ai.findPropertiesToIgnore(beanDesc.getClassInfo(), false)); deser = md; } } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java index eb38dde46d..8e8c48fa5a 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java @@ -618,7 +618,7 @@ public JsonDeserializer createContextual(DeserializationContext ctxt, } // And possibly add more properties to ignore if (accessor != null) { - String[] ignorals = intr.findPropertiesToIgnore(accessor); + String[] ignorals = intr.findPropertiesToIgnore(accessor, false); if (ignorals != null && ignorals.length != 0) { HashSet newIgnored = ArrayBuilders.setAndArray(contextual._ignorableProps, ignorals); contextual = contextual.withIgnorableProperties(newIgnored); diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerFactory.java index 8b0b6f0c55..89914835a1 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerFactory.java @@ -451,7 +451,7 @@ protected void addBeanProps(DeserializationContext ctxt, } } // Or explicit/implicit definitions? - Set ignored = ArrayBuilders.arrayToSet(intr.findPropertiesToIgnore(beanDesc.getClassInfo())); + Set ignored = ArrayBuilders.arrayToSet(intr.findPropertiesToIgnore(beanDesc.getClassInfo(), false)); for (String propName : ignored) { builder.addIgnorable(propName); } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/MapDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/MapDeserializer.java index aaec054fb4..69c0d3febd 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/MapDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/MapDeserializer.java @@ -254,7 +254,7 @@ public JsonDeserializer createContextual(DeserializationContext ctxt, if (intr != null && property != null) { AnnotatedMember member = property.getMember(); if (member != null) { - String[] moreToIgnore = intr.findPropertiesToIgnore(member); + String[] moreToIgnore = intr.findPropertiesToIgnore(member, false); if (moreToIgnore != null) { ignored = (ignored == null) ? new HashSet() : new HashSet(ignored); for (String str : moreToIgnore) { 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 13e8603cbe..c1c9d2c7ae 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotationIntrospectorPair.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotationIntrospectorPair.java @@ -113,8 +113,8 @@ public PropertyName findRootName(AnnotatedClass ac) } @Override - public String[] findPropertiesToIgnore(Annotated ac) - { + @Deprecated // since 2.6 + public String[] findPropertiesToIgnore(Annotated ac) { String[] result = _primary.findPropertiesToIgnore(ac); if (result == null) { result = _secondary.findPropertiesToIgnore(ac); @@ -122,6 +122,15 @@ public String[] findPropertiesToIgnore(Annotated ac) return result; } + @Override + public String[] findPropertiesToIgnore(Annotated ac, boolean forSerialization) { + String[] result = _primary.findPropertiesToIgnore(ac, forSerialization); + if (result == null) { + result = _secondary.findPropertiesToIgnore(ac, forSerialization); + } + return result; + } + @Override public Boolean findIgnoreUnknownProperties(AnnotatedClass ac) { diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java index fe37b17328..73f3ce2981 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java @@ -81,11 +81,31 @@ public PropertyName findRootName(AnnotatedClass ac) } @Override + @Deprecated // since 2.6, remove from 2.7 or later public String[] findPropertiesToIgnore(Annotated ac) { JsonIgnoreProperties ignore = _findAnnotation(ac, JsonIgnoreProperties.class); return (ignore == null) ? null : ignore.value(); } + @Override // since 2.6 + public String[] findPropertiesToIgnore(Annotated ac, boolean forSerialization) { + JsonIgnoreProperties ignore = _findAnnotation(ac, JsonIgnoreProperties.class); + if (ignore == null) { + return null; + } + // 13-May-2015, tatu: As per [databind#95], allow read-only/write-only props + if (forSerialization) { + if (ignore.allowGetters()) { + return null; + } + } else { + if (ignore.allowSetters()) { + return null; + } + } + return ignore.value(); + } + @Override public Boolean findIgnoreUnknownProperties(AnnotatedClass ac) { JsonIgnoreProperties ignore = _findAnnotation(ac, JsonIgnoreProperties.class); diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/BasicSerializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/ser/BasicSerializerFactory.java index 7938d6aab3..69a515d0c6 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/BasicSerializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/BasicSerializerFactory.java @@ -761,7 +761,8 @@ protected JsonSerializer buildMapSerializer(SerializationConfig config, } else { */ Object filterId = findFilterId(config, beanDesc); - MapSerializer mapSer = MapSerializer.construct(config.getAnnotationIntrospector().findPropertiesToIgnore(beanDesc.getClassInfo()), + AnnotationIntrospector ai = config.getAnnotationIntrospector(); + MapSerializer mapSer = MapSerializer.construct(ai.findPropertiesToIgnore(beanDesc.getClassInfo(), true), type, staticTyping, elementTypeSerializer, keySerializer, elementValueSerializer, filterId); Object suppressableValue = findSuppressableContentValue(config, diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java index 2bbf2d613c..f32a47c2f8 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java @@ -587,7 +587,7 @@ protected List filterBeanProperties(SerializationConfig conf { AnnotationIntrospector intr = config.getAnnotationIntrospector(); AnnotatedClass ac = beanDesc.getClassInfo(); - String[] ignored = intr.findPropertiesToIgnore(ac); + String[] ignored = intr.findPropertiesToIgnore(ac, true); if (ignored != null && ignored.length > 0) { HashSet ignoredSet = ArrayBuilders.arrayToSet(ignored); Iterator it = props.iterator(); diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java index 53e1de8553..1d40930bd8 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java @@ -420,7 +420,7 @@ public JsonSerializer createContextual(SerializerProvider provider, // Then we may have an override for Object Id if (accessor != null) { - ignorals = intr.findPropertiesToIgnore(accessor); + ignorals = intr.findPropertiesToIgnore(accessor, true); ObjectIdInfo objectIdInfo = intr.findObjectIdInfo(accessor); if (objectIdInfo == null) { // no ObjectId override, but maybe ObjectIdRef? diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/MapSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/MapSerializer.java index 722bfde1a8..9dd181000a 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/std/MapSerializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/MapSerializer.java @@ -356,7 +356,7 @@ public JsonSerializer createContextual(SerializerProvider provider, HashSet ignored = _ignoredEntries; boolean sortKeys = false; if (intr != null && propertyAcc != null) { - String[] moreToIgnore = intr.findPropertiesToIgnore(propertyAcc); + String[] moreToIgnore = intr.findPropertiesToIgnore(propertyAcc, true); if (moreToIgnore != null) { ignored = (ignored == null) ? new HashSet() : new HashSet(ignored); for (String str : moreToIgnore) { diff --git a/src/test/java/com/fasterxml/jackson/databind/filter/TestIgnorePropsForSerialization.java b/src/test/java/com/fasterxml/jackson/databind/filter/IgnorePropsTest.java similarity index 98% rename from src/test/java/com/fasterxml/jackson/databind/filter/TestIgnorePropsForSerialization.java rename to src/test/java/com/fasterxml/jackson/databind/filter/IgnorePropsTest.java index 9c1c757271..035976ffd7 100644 --- a/src/test/java/com/fasterxml/jackson/databind/filter/TestIgnorePropsForSerialization.java +++ b/src/test/java/com/fasterxml/jackson/databind/filter/IgnorePropsTest.java @@ -6,7 +6,7 @@ import com.fasterxml.jackson.databind.*; -public class TestIgnorePropsForSerialization +public class IgnorePropsTest extends BaseMapTest { @JsonIgnoreProperties({"b", "c"}) @@ -63,7 +63,7 @@ static class MapWrapper { value.put("b", 2); } } - + /* /**************************************************************** /* Unit tests diff --git a/src/test/java/com/fasterxml/jackson/databind/filter/ReadOnlyProperties95Test.java b/src/test/java/com/fasterxml/jackson/databind/filter/ReadOnlyProperties95Test.java new file mode 100644 index 0000000000..a00b5c69f6 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/filter/ReadOnlyProperties95Test.java @@ -0,0 +1,29 @@ +package com.fasterxml.jackson.databind.filter; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.*; + +/** + * Failing test related to [databind#95] + */ +public class ReadOnlyProperties95Test extends BaseMapTest +{ + @JsonIgnoreProperties(value={ "computed" }, allowGetters=true) + static class ReadOnlyBean + { + public int value = 3; + + public int getComputed() { return 32; } + } + + public void testReadOnlyProp() throws Exception + { + ObjectMapper m = new ObjectMapper(); + String json = m.writeValueAsString(new ReadOnlyBean()); + if (json.indexOf("computed") < 0) { + fail("Should have property 'computed', didn't: "+json); + } + ReadOnlyBean bean = m.readValue(json, ReadOnlyBean.class); + assertNotNull(bean); + } +}