001package io.avaje.jsonb; 002 003import static java.lang.annotation.RetentionPolicy.CLASS; 004import static java.lang.annotation.RetentionPolicy.RUNTIME; 005 006import java.lang.annotation.ElementType; 007import java.lang.annotation.Repeatable; 008import java.lang.annotation.Retention; 009import java.lang.annotation.Target; 010 011/** 012 * Marks a type for JSON support. 013 * 014 * <h3>Examples:</h3> 015 * 016 * <pre>{@code 017 * 018 * @Json(naming = LowerHyphen) 019 * public class Customer ... 020 * 021 * }</pre> 022 * 023 * <pre>{@code 024 * 025 * @Json 026 * public record Product( ... ) 027 * 028 * }</pre> 029 */ 030@Retention(CLASS) 031@Target(ElementType.TYPE) 032public @interface Json { 033 034 /** 035 * Specify the naming convention to use for the properties on this type. 036 * <p> 037 * By default, the naming used is {@link Naming#Match} 038 */ 039 Naming naming() default Naming.Match; 040 041 /** 042 * When {@code @Json.SubType} is used this specifies the name of the property 043 * field that holds the type name (discriminator value). 044 * <p> 045 * This defaults to {@code @type} when unspecified. 046 */ 047 String typeProperty() default ""; 048 049 /** 050 * When set to true on deserialization keys are matched insensitive to case. 051 */ 052 boolean caseInsensitiveKeys() default false; 053 054 /** 055 * Specify types to generate JsonAdapters for. 056 * <p> 057 * These types are typically in an external project / dependency or otherwise 058 * types that we can't or don't want to explicitly annotate with {@code @Json}. 059 * <p> 060 * Typically, we put this annotation on a package. 061 * 062 * <pre>{@code 063 * 064 * @Json.Import({Customer.class, Product.class, ...}) 065 * package org.example.processor; 066 * 067 * }</pre> 068 */ 069 @Retention(CLASS) 070 @Target({ElementType.TYPE, ElementType.PACKAGE}) 071 @interface Import { 072 073 /** 074 * Specify types to generate Json Adapters for. 075 */ 076 Class<?>[] value(); 077 } 078 079 /** 080 * Override the json property name. 081 * 082 * <pre>{@code 083 * 084 * @Json.Property("$code") 085 * String referenceCode; 086 * 087 * }</pre> 088 */ 089 @Retention(CLASS) 090 @Target({ElementType.FIELD}) 091 @interface Property { 092 093 /** 094 * Specify the name for this property. 095 */ 096 String value(); 097 } 098 099 /** 100 * Define one or more alternative names for a property accepted 101 * during deserialization. 102 * 103 * <pre>{@code 104 * @Json.JsonAlias("$code") 105 * String referenceCode; 106 * 107 * }</pre> 108 */ 109 @Retention(CLASS) 110 @Target({ElementType.FIELD}) 111 @interface JsonAlias { 112 113 /** One or more secondary names to accept as aliases to the official name. */ 114 String[] value(); 115 } 116 117 /** 118 * Exclude the property from serialization, deserialization or both. 119 * <p> 120 * We can explicitly use {@code deserialize=true} to include the property in 121 * deserialization but not serialization. For example, we might do this on 122 * a property that represents a secret like a password. 123 * <p> 124 * We can explicitly use {@code serialize=true} to include the property in 125 * serialization but not deserialization. 126 */ 127 @Retention(CLASS) 128 @Target({ElementType.FIELD}) 129 @interface Ignore { 130 131 /** 132 * Set this explicitly to true to include in serialization. 133 */ 134 boolean serialize() default false; 135 136 /** 137 * Set this explicitly to true to include in deserialization. 138 */ 139 boolean deserialize() default false; 140 } 141 142 /** 143 * Annotate a {@code Map<String,Object>} field to hold unmapped json properties. 144 * <p> 145 * When reading unknown properties from json content these are read and put into 146 * this map. When writing json this map is included back into the content. 147 * 148 * <pre>{@code 149 * 150 * @Json.Unmapped 151 * Map<String, Object> unmapped; 152 * 153 * }</pre> 154 */ 155 @Retention(CLASS) 156 @Target({ElementType.FIELD}) 157 @interface Unmapped { 158 159 } 160 161 /** 162 * Mark a method on an Enum that provides the json value. 163 * <p> 164 * If the method returns an int type then it is mapped to json int, otherwise it is 165 * treated as providing json string values. 166 * 167 * <pre>{@code 168 * 169 * public enum MyEnum { 170 * 171 * ONE("one value"), 172 * TWO("two value"); 173 * 174 * final String val; 175 * MyEnum(String val) { 176 * this.val = val; 177 * } 178 * 179 * // method provides the values used to serialise to and from json 180 * 181 * @Json.Value 182 * public String value() { 183 * return val; 184 * } 185 * } 186 * 187 * }</pre> 188 */ 189 @Retention(RUNTIME) 190 @Target({ElementType.METHOD}) 191 @interface Value { 192 } 193 194 /** 195 * Specify the subtypes that a given type can be represented as. 196 * <p> 197 * This is used on an interface type, abstract type or type with inheritance 198 * to indicate all the concrete subtypes that can represent the type. 199 * <p> 200 * In the example below the abstract Vehicle type has 2 concrete subtypes 201 * of Car and Truck that can represent the type. 202 * 203 * <pre>{@code 204 * 205 * @Json 206 * @Json.SubType(type = Car.class) 207 * @Json.SubType(type = Truck.class, name = "TRUCK") 208 * public abstract class Vehicle { 209 * ... 210 * 211 * }</pre> 212 */ 213 @Retention(CLASS) 214 @Target({ElementType.TYPE}) 215 @Repeatable(SubTypes.class) 216 @interface SubType { 217 218 /** 219 * The concrete type that extends or implements the base type. 220 */ 221 Class<?> type(); 222 223 /** 224 * The name or "discriminator value" that is used to identify the type. 225 * <p> 226 * When unspecified this is the short name of the class. 227 */ 228 String name() default ""; 229 } 230 231 /** 232 * Container of all the concrete SubType's that an interface type or abstract 233 * type can be represented as. 234 */ 235 @Retention(CLASS) 236 @Target({ElementType.TYPE}) 237 @interface SubTypes { 238 239 SubType[] value(); 240 } 241 242 /** 243 * Marks a String field as containing raw JSON content. 244 */ 245 @Retention(CLASS) 246 @Target({ElementType.FIELD}) 247 @interface Raw { 248 249 } 250 251 /** 252 * Mark this Class as a MixIn Type that can add Jsonb Annotations on the specified type. 253 * <p> 254 * These types are typically in an external project / dependency or otherwise 255 * types that we can't or don't want to explicitly annotate with {@code @Json}. 256 * <p> 257 * In the example below, the VehicleMixin class augments the the generated Vehicle JsonB adapter to use "ford-type" as the json property. 258 * 259 * <pre>{@code 260 * 261 * @Json.MixIn(Vehicle.class) 262 * public abstract class VehicleMixIn { 263 * 264 * @Json.Property("ford-type") 265 * private String type; 266 * ... 267 * 268 * }</pre> 269 */ 270 @Retention(CLASS) 271 @Target({ElementType.TYPE}) 272 @interface MixIn { 273 /** The concrete type to mix. */ 274 Class<?> value(); 275 } 276 277 /** 278 * The naming convention that we can use for a given type. 279 */ 280 enum Naming { 281 Match, 282 LowerHyphen, 283 LowerUnderscore, 284 LowerSpace, 285 UpperCamel, 286 UpperHyphen, 287 UpperUnderscore, 288 UpperSpace 289 } 290 291}