001package io.avaje.jsonb;
002
003import java.lang.annotation.ElementType;
004import java.lang.annotation.Repeatable;
005import java.lang.annotation.Retention;
006import java.lang.annotation.Target;
007
008import static java.lang.annotation.RetentionPolicy.CLASS;
009import static java.lang.annotation.RetentionPolicy.RUNTIME;
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   * The naming convention that we can use for a given type.
230   */
231  enum Naming {
232    Match,
233    LowerHyphen,
234    LowerUnderscore,
235    LowerSpace,
236    UpperCamel,
237    UpperHyphen,
238    UpperUnderscore,
239    UpperSpace
240  }
241
242}