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}