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
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 }