1 package com.fasterxml.jackson.annotation;
2 
3 import java.lang.annotation.*;
4 import java.util.*;
5 
6 /**
7  * Annotation that can be used to either only include serialization of
8  * properties (during serialization), or only include processing of
9  * JSON properties read (during deserialization).
10  * <p>
11  * Example:
12  * <pre>
13  * // to only include specified fields from being serialized or deserialized
14  * // (i.e. only include in JSON output; or being set even if they were included)
15  * &#064;JsonIncludeProperties({ "internalId", "secretKey" })
16  * </pre>
17  * <p>
18  * Annotation can be applied both to classes and
19  * to properties. If used for both, actual set will be union of all
20  * includes: that is, you can only add properties to include, not remove
21  * or override. So you can not remove properties to include using
22  * per-property annotation.
23  *
24  * @since 2.12
25  */
26 @Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE,
27         ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
28 @Retention(RetentionPolicy.RUNTIME)
29 @JacksonAnnotation
30 public @interface JsonIncludeProperties
31 {
32     /**
33      * Names of properties to include.
34      */
value()35     public String[] value() default {};
36 
37     /*
38     /**********************************************************
39     /* Value class used to enclose information, allow for
40     /* merging of layered configuration settings.
41     /**********************************************************
42      */
43 
44     /**
45      * Helper class used to contain information from a single {@link JsonIncludeProperties}
46      * annotation, as well as to provide possible overrides from non-annotation sources.
47      *
48      * @since 2.12
49      */
50     public static class Value implements JacksonAnnotationValue<JsonIncludeProperties>, java.io.Serializable
51     {
52         private static final long serialVersionUID = 1L;
53 
54         /**
55          * Default instance has no explicitly included fields
56          */
57         protected final static JsonIncludeProperties.Value ALL = new JsonIncludeProperties.Value(null);
58 
59         /**
60          * Name of the properties to include.
61          * Null means that all properties are included, empty means none.
62          */
63         protected final Set<String> _included;
64 
Value(Set<String> included)65         protected Value(Set<String> included)
66         {
67             _included = included;
68         }
69 
from(JsonIncludeProperties src)70         public static JsonIncludeProperties.Value from(JsonIncludeProperties src)
71         {
72             if (src == null) {
73                 return ALL;
74             }
75             return new Value(_asSet(src.value()));
76         }
77 
all()78         public static JsonIncludeProperties.Value all()
79         {
80             return ALL;
81         }
82 
83         @Override
valueFor()84         public Class<JsonIncludeProperties> valueFor()
85         {
86             return JsonIncludeProperties.class;
87         }
88 
89         /**
90          * @return Names included, if any, possibly empty; {@code null} for "not defined"
91          */
getIncluded()92         public Set<String> getIncluded()
93         {
94             return _included;
95         }
96 
97         /**
98          * Mutant factory method to override the current value with an another,
99          * merging the included fields so that only entries that exist in both original
100          * and override set are included, taking into account that "undefined" {@link Value}s
101          * do not count ("undefined" meaning that {@code getIncluded()} returns {@code null}).
102          * So: overriding with "undefined" returns original {@code Value} as-is; overriding an
103          * "undefined" {@code Value} returns override {@code Value} as-is.
104          */
withOverrides(JsonIncludeProperties.Value overrides)105         public JsonIncludeProperties.Value withOverrides(JsonIncludeProperties.Value overrides)
106         {
107             final Set<String> otherIncluded;
108 
109             if (overrides == null || (otherIncluded = overrides.getIncluded()) == null) {
110                 return this;
111             }
112 
113             if (_included == null) {
114                 return overrides;
115             }
116 
117             HashSet<String> toInclude = new HashSet<String>();
118             for (String incl : otherIncluded) {
119                 if (_included.contains(incl)) {
120                     toInclude.add(incl);
121                 }
122             }
123 
124             return new JsonIncludeProperties.Value(toInclude);
125         }
126 
127         @Override
toString()128         public String toString() {
129             return String.format("JsonIncludeProperties.Value(included=%s)",
130                     _included);
131         }
132 
133         @Override
hashCode()134         public int hashCode() {
135             return (_included == null) ? 0 : _included.size();
136         }
137 
138         @Override
equals(Object o)139         public boolean equals(Object o) {
140             if (o == this) return true;
141             if (o == null) return false;
142             return (o.getClass() == getClass()) && _equals(_included, ((Value) o)._included);
143         }
144 
_equals(Set<String> a, Set<String> b)145         private static boolean _equals(Set<String> a, Set<String> b)
146         {
147             return a == null ? (b == null)
148                     // keep this last just because it can be expensive
149                     : a.equals(b);
150         }
151 
_asSet(String[] v)152         private static Set<String> _asSet(String[] v)
153         {
154             if (v == null || v.length == 0) {
155                 return Collections.emptySet();
156             }
157             Set<String> s = new HashSet<String>(v.length);
158             for (String str : v) {
159                 s.add(str);
160             }
161             return s;
162         }
163     }
164 }
165