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}