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 * @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