View Javadoc

1   package com.atlassian.plugins.rest.doclet.generators.schema;
2   
3   import com.atlassian.annotations.tenancy.TenantAware;
4   import com.atlassian.plugins.rest.doclet.generators.schema.Schema.Type;
5   import com.google.common.base.Objects;
6   import com.google.common.collect.ImmutableMap;
7   import org.codehaus.jackson.annotate.JsonRawValue;
8   import org.joda.time.DateTime;
9   
10  import java.lang.reflect.AnnotatedElement;
11  import java.net.URI;
12  import java.util.Date;
13  import java.util.Map;
14  import java.util.Optional;
15  
16  import static com.atlassian.annotations.tenancy.TenancyScope.TENANTLESS;
17  
18  public class Types {
19  
20      private Types() {}
21  
22      @TenantAware(TENANTLESS)
23      private static final Map<Class<?>, Type> classToJsonType;
24  
25      static {
26          ImmutableMap.Builder<Class<?>, Type> builder = ImmutableMap.<Class<?>, Type>builder()
27                  .put(String.class, Type.String)
28                  .put(Integer.class, Type.Integer)
29                  .put(Long.class, Type.Integer)
30                  .put(Number.class, Type.Number)
31                  .put(Boolean.class, Type.Boolean)
32                  .put(URI.class, Type.Uri)
33                  .put(Enum.class, Type.String)
34                  .put(Date.class, Type.String);
35          try {
36              builder.put(DateTime.class, Type.String);
37          } catch (NoClassDefFoundError notFound) {
38              // joda is not present, doesn't matter
39          }
40  
41          classToJsonType = builder.build();
42      }
43  
44      @TenantAware(TENANTLESS)
45      private static final Map<String, Type> primitiveTypeToJsonType = ImmutableMap.<String, Type>builder()
46              .put("boolean", Type.Boolean)
47              .put("int", Type.Integer)
48              .put("short", Type.Integer)
49              .put("long", Type.Integer)
50              .put("double", Type.Number)
51              .put("float", Type.Number)
52              .put("char", Type.String)
53              .put("byte", Type.Integer)
54              .build();
55  
56      public static Type resolveType(final RichClass modelClass, final AnnotatedElement containingField) {
57          if (containingField != null && containingField.isAnnotationPresent(JsonRawValue.class)) {
58              return Type.Any;
59          } else if (isPrimitive(modelClass.getActualClass())) {
60              return getPrimitiveType(modelClass.getActualClass()).get();
61          } else if (isCollection(modelClass)) {
62              return Type.Array;
63          } else if (modelClass.getActualClass() == Object.class) {
64              return Type.Any;
65          } else {
66              return Type.Object;
67          }
68      }
69  
70      public static boolean isPrimitive(Class<?> modelClass) {
71          return getPrimitiveType(modelClass).isPresent();
72      }
73  
74      private static Optional<Type> getPrimitiveType(Class<?> modelClass) {
75          for (Map.Entry<Class<?>, Type> classToTypeName : classToJsonType.entrySet()) {
76              if (classToTypeName.getKey().isAssignableFrom(modelClass)) {
77                  return Optional.of(classToTypeName.getValue());
78              }
79          }
80  
81          if (modelClass.isPrimitive()) {
82              Type mapped = primitiveTypeToJsonType.get(modelClass.getSimpleName());
83              return Optional.of(Objects.firstNonNull(mapped, Type.String));
84          }
85  
86          return Optional.empty();
87      }
88  
89      public static boolean isCollection(final RichClass type) {
90          return type.getActualClass().isArray() || Iterable.class.isAssignableFrom(type.getActualClass()) && !type.getGenericTypes().isEmpty();
91      }
92  
93      public static boolean isJDKClass(final Class<?> type) {
94          String name = type.getCanonicalName() != null ? type.getCanonicalName() : type.getName();
95          return name.startsWith("java");
96      }
97  }