aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBaptiste Pernet <pernetmu@gmail.com>2020-07-22 18:55:48 -0700
committerGitHub <noreply@github.com>2020-07-22 18:55:48 -0700
commitdcf82b795ced2e570ba70bfe087d138d9033ea20 (patch)
tree935867873dd5079bb782a58f3e320774df837b3b
parent8dac7ceaccd66cb76a4ce40a31340f7d385ae1bd (diff)
downloadjackson-annotations-dcf82b795ced2e570ba70bfe087d138d9033ea20.tar.gz
FasterXML/jackson-databind#1296 @JsonIncludeProperties (#174)
Add `@JsonIncludeProperties`
-rw-r--r--src/main/java/com/fasterxml/jackson/annotation/JsonIncludeProperties.java167
-rw-r--r--src/test/java/com/fasterxml/jackson/annotation/JsonIncludePropertiesTest.java68
2 files changed, 235 insertions, 0 deletions
diff --git a/src/main/java/com/fasterxml/jackson/annotation/JsonIncludeProperties.java b/src/main/java/com/fasterxml/jackson/annotation/JsonIncludeProperties.java
new file mode 100644
index 0000000..1ffaec5
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/annotation/JsonIncludeProperties.java
@@ -0,0 +1,167 @@
+package com.fasterxml.jackson.annotation;
+
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
+import javax.swing.text.html.HTMLDocument;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * Annotation that can be used to either only include serialization of
+ * properties (during serialization), or only include processing of
+ * JSON properties read (during deserialization).
+ * <p>
+ * Example:
+ * <pre>
+ * // to only include specified fields from being serialized or deserialized
+ * // (i.e. only include in JSON output; or being set even if they were included)
+ * &#064;JsonIncludeProperties({ "internalId", "secretKey" })
+ * </pre>
+ * <p>
+ * Annotation can be applied both to classes and
+ * to properties. If used for both, actual set will be union of all
+ * includes: that is, you can only add properties to include, not remove
+ * or override. So you can not remove properties to include using
+ * per-property annotation.
+ *
+ * @since 2.12
+ */
+@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE,
+ ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@JacksonAnnotation
+public @interface JsonIncludeProperties
+{
+ /**
+ * Names of properties to include.
+ */
+ public String[] value() default {};
+
+ /*
+ /**********************************************************
+ /* Value class used to enclose information, allow for
+ /* merging of layered configuration settings.
+ /**********************************************************
+ */
+
+ /**
+ * Helper class used to contain information from a single {@link JsonIncludeProperties}
+ * annotation, as well as to provide possible overrides from non-annotation sources.
+ *
+ * @since 2.12
+ */
+ public static class Value implements JacksonAnnotationValue<JsonIncludeProperties>, java.io.Serializable
+ {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Default instance has no explicitly included fields
+ */
+ protected final static JsonIncludeProperties.Value ALL = new JsonIncludeProperties.Value(null);
+
+ /**
+ * Name of the properties to include.
+ * Null means that all properties are included, empty means none.
+ */
+ protected final Set<String> _included;
+
+ protected Value(Set<String> included)
+ {
+ _included = included;
+ }
+
+ public static JsonIncludeProperties.Value from(JsonIncludeProperties src)
+ {
+ if (src == null) {
+ return ALL;
+ }
+
+ return new Value(_asSet(src.value()));
+ }
+
+ public static JsonIncludeProperties.Value all()
+ {
+ return ALL;
+ }
+
+ @Override
+ public Class<JsonIncludeProperties> valueFor()
+ {
+ return JsonIncludeProperties.class;
+ }
+
+ public Set<String> getIncluded()
+ {
+ return _included;
+ }
+
+ /**
+ * Mutant factory method to override the current value with an another, merging the included fields.
+ */
+ public JsonIncludeProperties.Value withOverrides(JsonIncludeProperties.Value overrides) {
+ if (overrides == null || overrides.getIncluded() == null) {
+ return this;
+ }
+
+ if (_included == null) {
+ return overrides;
+ }
+
+ HashSet<String> included = new HashSet<String>(_included);
+ Iterator<String> iterator = included.iterator();
+ while (iterator.hasNext()) {
+ if (!overrides.getIncluded().contains(iterator.next())) {
+ iterator.remove();
+ }
+ }
+
+ return new JsonIncludeProperties.Value(new HashSet<String>(included));
+ }
+
+ @Override
+ public String toString() {
+ return String.format("JsonIncludeProperties.Value(included=%s)",
+ _included);
+ }
+
+ @Override
+ public int hashCode() {
+ return (_included == null ? 0 : _included.size())
+ ;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null) return false;
+ return (o.getClass() == getClass())
+ && _equals(this, (Value) o);
+ }
+
+ private static boolean _equals(Value a, Value b)
+ {
+ return a._included == null ? b._included == null :
+ // keep this last just because it can be expensive
+ a._included.equals(b._included)
+ ;
+ }
+
+ private static Set<String> _asSet(String[] v)
+ {
+ if (v == null || v.length == 0) {
+ return Collections.emptySet();
+ }
+ Set<String> s = new HashSet<String>(v.length);
+ for (String str : v) {
+ s.add(str);
+ }
+ return s;
+ }
+ }
+}
diff --git a/src/test/java/com/fasterxml/jackson/annotation/JsonIncludePropertiesTest.java b/src/test/java/com/fasterxml/jackson/annotation/JsonIncludePropertiesTest.java
new file mode 100644
index 0000000..55ae738
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/annotation/JsonIncludePropertiesTest.java
@@ -0,0 +1,68 @@
+package com.fasterxml.jackson.annotation;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * Tests to verify that it is possibly to merge {@link JsonIncludeProperties.Value}
+ * instances for overrides
+ */
+public class JsonIncludePropertiesTest extends TestBase
+{
+ @JsonIncludeProperties(value = {"foo", "bar"})
+ private final static class Bogus
+ {
+ }
+
+ private final JsonIncludeProperties.Value ALL = JsonIncludeProperties.Value.all();
+
+ public void testAll()
+ {
+ assertSame(ALL, JsonIncludeProperties.Value.from(null));
+ assertNull(ALL.getIncluded());
+ assertEquals(ALL, ALL);
+ assertEquals("JsonIncludeProperties.Value(included=null)", ALL.toString());
+ assertEquals(0, ALL.hashCode());
+ }
+
+ public void testFromAnnotation()
+ {
+ JsonIncludeProperties.Value v = JsonIncludeProperties.Value.from(Bogus.class.getAnnotation(JsonIncludeProperties.class));
+ assertNotNull(v);
+ Set<String> included = v.getIncluded();
+ assertEquals(2, v.getIncluded().size());
+ assertEquals(_set("foo", "bar"), included);
+ assertEquals("JsonIncludeProperties.Value(included=[bar, foo])", v.toString());
+ assertEquals(v, JsonIncludeProperties.Value.from(Bogus.class.getAnnotation(JsonIncludeProperties.class)));
+ }
+
+ public void testWithOverridesAll() {
+ JsonIncludeProperties.Value v = JsonIncludeProperties.Value.from(Bogus.class.getAnnotation(JsonIncludeProperties.class));
+ v = v.withOverrides(ALL);
+ Set<String> included = v.getIncluded();
+ assertEquals(2, included.size());
+ assertEquals(_set("foo", "bar"), included);
+ }
+
+ public void testWithOverridesEmpty() {
+ JsonIncludeProperties.Value v = JsonIncludeProperties.Value.from(Bogus.class.getAnnotation(JsonIncludeProperties.class));
+ v = v.withOverrides(new JsonIncludeProperties.Value(Collections.<String>emptySet()));
+ Set<String> included = v.getIncluded();
+ assertEquals(0, included.size());
+ }
+
+ public void testWithOverridesMerge() {
+ JsonIncludeProperties.Value v = JsonIncludeProperties.Value.from(Bogus.class.getAnnotation(JsonIncludeProperties.class));
+ v = v.withOverrides(new JsonIncludeProperties.Value(_set("foo")));
+ Set<String> included = v.getIncluded();
+ assertEquals(1, included.size());
+ assertEquals(_set("foo"), included);
+ }
+
+ private Set<String> _set(String... args)
+ {
+ return new LinkedHashSet<String>(Arrays.asList(args));
+ }
+}