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 * Specify types to generate JsonAdapters for. 051 * <p> 052 * These types are typically in an external project / dependency or otherwise 053 * types that we can't or don't want to explicitly annotate with {@code @Json}. 054 * <p> 055 * Typically, we put this annotation on a package. 056 * 057 * <pre>{@code 058 * 059 * @Json.Import({Customer.class, Product.class, ...}) 060 * package org.example.processor; 061 * 062 * }</pre> 063 */ 064 @Retention(CLASS) 065 @Target({ElementType.TYPE, ElementType.PACKAGE}) 066 @interface Import { 067 068 /** 069 * Specify types to generate Json Adapters for. 070 */ 071 Class<?>[] value(); 072 } 073 074 /** 075 * Override the json property name. 076 * 077 * <pre>{@code 078 * 079 * @Json.Property("$code") 080 * String referenceCode; 081 * 082 * }</pre> 083 */ 084 @Retention(CLASS) 085 @Target({ElementType.FIELD}) 086 @interface Property { 087 088 /** 089 * Specify the name for this property. 090 */ 091 String value(); 092 } 093 094 /** 095 * Exclude the property from serialization, deserialization or both. 096 * <p> 097 * We can explicitly use {@code deserialize=true} to include the property in 098 * deserialization but not serialization. For example, we might do this on 099 * a property that represents a secret like a password. 100 * <p> 101 * We can explicitly use {@code serialize=true} to include the property in 102 * serialization but not deserialization. 103 */ 104 @Retention(CLASS) 105 @Target({ElementType.FIELD}) 106 @interface Ignore { 107 108 /** 109 * Set this explicitly to true to include in serialization. 110 */ 111 boolean serialize() default false; 112 113 /** 114 * Set this explicitly to true to include in deserialization. 115 */ 116 boolean deserialize() default false; 117 } 118 119 /** 120 * Annotate a {@code Map<String,Object>} field to hold unmapped json properties. 121 * <p> 122 * When reading unknown properties from json content these are read and put into 123 * this map. When writing json this map is included back into the content. 124 * 125 * <pre>{@code 126 * 127 * @Json.Unmapped 128 * Map<String, Object> unmapped; 129 * 130 * }</pre> 131 */ 132 @Retention(CLASS) 133 @Target({ElementType.FIELD}) 134 @interface Unmapped { 135 136 } 137 138 /** 139 * Mark a method on an Enum that provides the json value. 140 * <p> 141 * If the method returns an int type then it is mapped to json int, otherwise it is 142 * treated as providing json string values. 143 * 144 * <pre>{@code 145 * 146 * public enum MyEnum { 147 * 148 * ONE("one value"), 149 * TWO("two value"); 150 * 151 * final String val; 152 * MyEnum(String val) { 153 * this.val = val; 154 * } 155 * 156 * // method provides the values used to serialise to and from json 157 * 158 * @Json.Value 159 * public String value() { 160 * return val; 161 * } 162 * } 163 * 164 * }</pre> 165 */ 166 @Retention(RUNTIME) 167 @Target({ElementType.METHOD}) 168 @interface Value { 169 } 170 171 /** 172 * Specify the subtypes that a given type can be represented as. 173 * <p> 174 * This is used on an interface type, abstract type or type with inheritance 175 * to indicate all the concrete subtypes that can represent the type. 176 * <p> 177 * In the example below the abstract Vehicle type has 2 concrete subtypes 178 * of Car and Truck that can represent the type. 179 * 180 * <pre>{@code 181 * 182 * @Json 183 * @Json.SubType(type = Car.class) 184 * @Json.SubType(type = Truck.class, name = "TRUCK") 185 * public abstract class Vehicle { 186 * ... 187 * 188 * }</pre> 189 */ 190 @Retention(CLASS) 191 @Target({ElementType.TYPE}) 192 @Repeatable(SubTypes.class) 193 @interface SubType { 194 195 /** 196 * The concrete type that extends or implements the base type. 197 */ 198 Class<?> type(); 199 200 /** 201 * The name or "discriminator value" that is used to identify the type. 202 * <p> 203 * When unspecified this is the short name of the class. 204 */ 205 String name() default ""; 206 } 207 208 /** 209 * Container of all the concrete SubType's that an interface type or abstract 210 * type can be represented as. 211 */ 212 @Retention(CLASS) 213 @Target({ElementType.TYPE}) 214 @interface SubTypes { 215 216 SubType[] value(); 217 } 218 219 /** 220 * Marks a String field as containing raw JSON content. 221 */ 222 @Retention(CLASS) 223 @Target({ElementType.FIELD}) 224 @interface Raw { 225 226 } 227 228 /** 229 * Mark this Class as a MixIn Type that can add Jsonb Annotations on the specified type. 230 * <p> 231 * These types are typically in an external project / dependency or otherwise 232 * types that we can't or don't want to explicitly annotate with {@code @Json}. 233 * <p> 234 * In the example below, the VehicleMixin class augments the the generated Vehicle JsonB adapter to use "ford-type" as the json property. 235 * 236 * <pre>{@code 237 * 238 * @Json.MixIn(Vehicle.class) 239 * public abstract class VehicleMixIn { 240 * 241 * @Json.Property("ford-type") 242 * private String type; 243 * ... 244 * 245 * }</pre> 246 */ 247 @Retention(CLASS) 248 @Target({ElementType.TYPE}) 249 @interface MixIn { 250 /** The concrete type to mix. */ 251 Class<?> value(); 252 } 253 254 /** 255 * The naming convention that we can use for a given type. 256 */ 257 enum Naming { 258 Match, 259 LowerHyphen, 260 LowerUnderscore, 261 LowerSpace, 262 UpperCamel, 263 UpperHyphen, 264 UpperUnderscore, 265 UpperSpace 266 } 267 268}