SHARE
TWEET

Untitled

a guest Feb 21st, 2020 77 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. public interface Source {
  2.  
  3.     @Nullable
  4.     Object getNullable(String key);
  5.  
  6.     @NonNull
  7.     default Object get(String key) {
  8.         final var result = getNullable(key);
  9.         if (result == null) {
  10.             throw new TypeException(key, ClassType.of(Object.class));
  11.         }
  12.         return result;
  13.     }
  14.  
  15. }
  16.  
  17. public interface Type<T> {
  18.  
  19.     @NonNull
  20.     T convert(@Nullable Object value, @NonNull Source source);
  21.  
  22.     static Type<?> of(java.lang.reflect.Type nativeType) {
  23.         if (nativeType instanceof Class) {
  24.             return of((Class<?>) nativeType);
  25.         }
  26.         final var p = (ParameterizedType) nativeType;
  27.         final var r = p.getRawType();
  28.         final var a = p.getActualTypeArguments();
  29.         if (r == Set.class) {
  30.             return new SetType<>(of(a[0]));
  31.         }
  32.         if (r == List.class || r == Collection.class) {
  33.             return new ListType<>(of(a[0]));
  34.         }
  35.         if (r == Map.class) {
  36.             return new MapType<>(of(a[0]), of(b[0]));
  37.         }
  38.         throw new IllegalArgumentException(nativeType.getTypeName());
  39.     }
  40.  
  41.     static <T> Type<T> of(Class<T> clazz) {
  42.         return ClassType.of(clazz);
  43.     }
  44.  
  45. }
  46.  
  47. public class AbstractType<T> implements Type<T> {
  48.  
  49.     @NonNull
  50.     public T convert(@Nullable Object value, @NonNull Source source) {
  51.         return Objects.requireNonNull(convert0(value, source));
  52.     }
  53.  
  54.     protected abstract boolean isInstance(@Nullable Object value);
  55.  
  56.     protected abstract Optional<Object> doConversion(@Nullable Object value, @NonNull Source source);
  57.  
  58.     @SuppressWarnings("unchecked")
  59.     private T convert0(Object value, Source source) {
  60.         if (isInstance(value)) {
  61.             return (T) value;
  62.         }
  63.         return (T) doConversion(value, source)
  64.             .or(() -> lookup(value, source)
  65.             .orElseThrow(() -> new TypeError(value, this));
  66.     }
  67.  
  68.     private Optional<Object> lookup(Object value, Source source) {
  69.         if (value instanceof String) {
  70.             final var base = source.get((String) value);
  71.             final var result = convert0(base, source);
  72.             return Optional.ofNullable(result);
  73.         }
  74.         return Optional.empty();
  75.     }
  76.  
  77. }
  78.  
  79. public class ClassType<T> extends AbstractType<T> {
  80.  
  81.     private static final Map<Class<?>, ClassType<?>> CACHE = new ConcurrentHashMap<>(Map.of
  82.         Boolean.class, BooleanType.BOOLEAN,
  83.         Integer.class, NumberType.INTEGER,
  84.         Double.class, NumberType.REAL,
  85.         String.class, StringType.STRING,
  86.         Object.class, ObjectType.DEFINED);
  87.  
  88.     final Class<T> clazz;
  89.  
  90.     ClassType(Class<T> clazz) {
  91.         this.clazz = Objects.requireNonNull(clazz);
  92.     }
  93.  
  94.     @SuppressWarnings("unchecked")
  95.     public static <T> ClassType<T> of(Class<T> clazz) {
  96.         return (ClassType) CACHE.computeIfAbsent(clazz, c -> {
  97.             if (c.isEnum()) {
  98.                 return new EnumClassType<>(c);
  99.             }
  100.             return new SimpleClassType<>(c);
  101.         });
  102.     }
  103.  
  104.     @Override
  105.     public int hashCode() {
  106.         return clazz.hashCode();
  107.     }
  108.  
  109.     @Override
  110.     public boolean equals(Object other) {
  111.         if (other == this) return true;
  112.         if (other == null || getClass() != other.getClass()) return false;
  113.         return clazz == ((ClassType<?>) other).clazz;
  114.     }
  115.  
  116.     @Override
  117.     public String toString() {
  118.         return clazz.getSimpleName();
  119.     }
  120.  
  121.     public Class<T> unwrap() {
  122.         return clazz;
  123.     }
  124.  
  125.     @Override
  126.     protected boolean isInstance(@Nullable Object value) {
  127.         return clazz.isInstance(value);
  128.     }
  129.  
  130. }
  131.  
  132. class SimpleClassType<T> extends ClassType<T> {
  133.  
  134.     SimpleClassType(Class<T> clazz) {
  135.         super(clazz);
  136.     }
  137.  
  138.     @Override
  139.     protected Optional<Object> doConversion(@Nullable Object value, @NonNull Source source) {
  140.         if (value == null) return doConversion(JSONObject.NULL, source);
  141.         // TODO: factory methods
  142.         return Optional.empty();
  143.     }
  144.  
  145. }
  146.  
  147. class EnumClassType<T> extends ClassType<T> {
  148.  
  149.     private final Map<String, T> map = new CaseInsensitiveMap<>();
  150.     private final Optional<Object> defaultValue;
  151.  
  152.     EnumClassType(Class<T> clazz) {
  153.         super(clazz);
  154.         for (final var t: clazz.getEnumConstants()) {
  155.             map.put(t.name(), t);
  156.         }
  157.         defaultValue = Optional
  158.                 .ofNullable(clazz.getAnnotation(Default.class))
  159.                 .map(Default::value)
  160.                 .map(map::get);
  161.     }
  162.  
  163.     @Override
  164.     protected Optional<Object> doConversion(@Nullable Object value, @NonNull Source source) {
  165.         if (value == null || value == JSONObject.NULL) return defaultValue;
  166.         return Optional.ofNullable(map.get(String.valueOf(value));
  167.     }
  168.  
  169. }
  170.  
  171. @Retention(RetentionPolicy.RUNTIME)
  172. @Target(ElementType.TYPE)
  173. public @interface Default {
  174.  
  175.     String value();
  176.  
  177. }
  178.  
  179. public abstract class CollectionType<E, C extends Collection<E>> extends Type<C> {
  180.  
  181.     private final Type<E> elementType;
  182.  
  183.     public CollectionType(@NonNull Type<E> elementType) {
  184.         this.elementType = Objects.requireNonNull(elementType);
  185.     }
  186.  
  187.     @NonNull @Override
  188.     public Set<E> convert(@Nullable Object value, @NonNull Source source) {
  189.         final var result = getEmptyMutableInstance();
  190.         if (value == null || value == JSONObject.NULL) {
  191.             return result;
  192.         }
  193.         if (value instanceof Iterable) {
  194.             for (final var i: (Iterable<?>) value) {
  195.                 result.add(elementType.convert(value, source));
  196.             }
  197.         } else {
  198.             result.add(elementType.convert(value, source));
  199.         }
  200.         return result;
  201.     }
  202.  
  203.     public Type<E> getElementType() {
  204.         return elementType;
  205.     }
  206.  
  207.     @Override
  208.     public int hashCode() {
  209.         return elementType.hashCode() * 7;
  210.     }
  211.  
  212.     @Override
  213.     public boolean equals(Object other) {
  214.         if (other == this) return true;
  215.         if (other == null || getClass() != other.getClass()) return false;
  216.         final var setType = (SetType<?>) other;
  217.         return elementType.equals(setType.elementType);
  218.     }
  219.  
  220.     protected abstract C getEmptyMutableInstance();
  221.  
  222. }
  223.  
  224. public class SetType<E> extends SetType<E> {
  225.  
  226.     public SetType(Type<E> elementType) {
  227.         super(elementType);
  228.     }
  229.  
  230.     @Override
  231.     public String toString() {
  232.         return String.format("{%s}", elementType);
  233.     }
  234.  
  235.     @Override
  236.     protected Set<E> getEmptyMutableInstance() {
  237.         return new HashSet<>();
  238.     }
  239.  
  240. }
  241.  
  242. public class ListType<E> extends ListType<E> {
  243.  
  244.     public ListType(Type<E> elementType) {
  245.         super(elementType);
  246.     }
  247.  
  248.     @Override
  249.     public String toString() {
  250.         return String.format("[%s]", elementType);
  251.     }
  252.  
  253.     @Override
  254.     protected List<E> getEmptyMutableInstance() {
  255.         return new ArrayList<>();
  256.     }
  257.  
  258. }
  259.  
  260. public class MapType<K, V> extends Type<Map<K, V>> {
  261.  
  262.     private final Type<K> keyType;
  263.     private final Type<V> valueType;
  264.  
  265.     public MapType(@NonNull Type<K> keyType, @NonNull Type<V> valueType) {
  266.         this.keyType = Objects.requireNonNull(keyType);
  267.         this.valueType = Objects.requireNonNull(valueType);
  268.     }
  269.  
  270.     @NonNull @Override
  271.     public Map<K, V> convert(@Nullable Object value, @NonNull Source source) {
  272.         if (value instanceof JSONObject) {
  273.             final var j = (JSONObject) value;
  274.             return convert(j.keySet(), j::get, source);
  275.         }
  276.         if (value instanceof Map) {
  277.             return convert((Map<?, ?>) value, source);
  278.         }
  279.         if (value == null || value == JSONObject.NULL) {
  280.             return Map.of();
  281.         }
  282.         throw new TypeException(value, this);
  283.     }
  284.  
  285.     public Type<K> getKeyType() {
  286.         return keyType;
  287.     }
  288.  
  289.     public Type<V> getValueType() {
  290.         return valueType;
  291.     }
  292.  
  293.     @Override
  294.     public int hashCode() {
  295.         return Objects.hash(keyType, valueType);
  296.     }
  297.  
  298.     @Override
  299.     public boolean equals(Object other) {
  300.         if (other == this) return true;
  301.         if (other == null || getClass() != other.getClass()) return false;
  302.         final var mapType = (MapType<?, ?>) other;
  303.         return keyType.equals(mapType.keyType)
  304.             && valueType.equals(mapType.valueType);
  305.     }
  306.  
  307.     @Override
  308.     public String toString() {
  309.         return String.format("{%s: %s}", keyType, valueType);
  310.     }
  311.  
  312.     private <T> Map<K, V> convert(Map<T, ?> map, Source source) {
  313.         return convert(map.keySet(), map::get, source);
  314.     }
  315.  
  316.     private <T> Map<K, V> convert(Set<T> keySet, Function<T, ?> get, Source source) {
  317.         final var result = new HashMap<K, V>(keySet.size());
  318.         for (final var i: keySet) {
  319.             final var k = keyType.convert(i, source);
  320.             final var v = valueType.convert(get.apply(i), source);
  321.             result.put(k, v);
  322.         }
  323.         return result;
  324.     }
  325.  
  326. }
  327.  
  328. public class UnionType<T, A extends U, B extends U> extends Type<T> {
  329.  
  330.     private final Type<A> leftType;
  331.     private final Type<B> rightType;
  332.  
  333.     public UnionType(Type<A> leftType, Type<B> rightType) {
  334.         this.leftType = leftType;
  335.         this.rightType = rightType;
  336.     }
  337.  
  338.     @Override
  339.     public T convert(@Nullable Object value, @NonNull Source source) {
  340.         try {
  341.             return leftType.convert(value, source);
  342.         } catch (final TypeException ignored) {}
  343.         try {
  344.             return rightType.convert(value, source);
  345.         } catch (final TypeException ignored) {
  346.             throw new TypeException(value, this);
  347.         }
  348.     };
  349.  
  350.     public Type<A> getLeftType() {
  351.         return leftType;
  352.     }
  353.  
  354.     public Type<B> getRightType() {
  355.         return rightType;
  356.     }
  357.  
  358.     @Override
  359.     public int hashCode() {
  360.         return Objects.hash(a, b);
  361.     }
  362.  
  363.     @Override
  364.     public boolean equals(Object other) {
  365.         if (other == this) return true;
  366.         if (other == null || getClass() != other.getClass()) return false;
  367.         final var unionType = (UnionType<?, ?, ?>) other;
  368.         return a.equals(unionType.a)
  369.             && b.equals(unionType.b);
  370.     }
  371.  
  372.     @Override
  373.     public String toString() {
  374.         return String.format("%s|%s", a, b);
  375.     }
  376.  
  377. }
  378.  
  379. public class ObjectType extends ClassType<Object> {
  380.  
  381.     public static final ObjectType DEFINED = new ObjectType();
  382.  
  383.     @NonNull @Override
  384.     protected boolean isInstance(@Nullable Object value) {
  385.         return value != null && value != JSONObject.NULL;
  386.     }
  387.  
  388.     @NonNull @Override
  389.     protected Optional<Object> doConversion(@Nullable Object value, @NonNull Source source) {
  390.         return Optional.empty();
  391.     }
  392.  
  393.     private ObjectType() {
  394.         super(Object.class);
  395.     }
  396.  
  397. }
  398.  
  399. public class BooleanType extends ClassType<Boolean> {
  400.  
  401.     private static final Set<Object> FALSE = Set.of(0, 0.0, JSONObject.NULL);
  402.  
  403.     public static final BooleanType BOOLEAN = new BooleanType();
  404.  
  405.     @NonNull @Override
  406.     protected Optional<Object> doConversion(@Nullable Object value, @NonNull Source source) {
  407.         return Optional.of("true".equalsIgnoreCase(String.valueOf(value));
  408.     }
  409.  
  410.     private BooleanType() {
  411.         super(Boolean.class);
  412.     }
  413.  
  414. }
  415.  
  416. public class NumberType<N> extends ClassType<N> {
  417.  
  418.     private final Function<String, N> callback;
  419.  
  420.     public static final NumberType<Double> REAL = new NumberType(Double.class, Double::valueOf);
  421.     public static final NumberType<Integer> INTEGER = new NumberType(Integer.class, Integer::decode);
  422.  
  423.     @NonNull @Override
  424.     protected Optional<Object> doConversion(@Nullable Object value, @NonNull Source source) {
  425.         if (value instanceof Collection) {
  426.             final var collection = (Collection<?>) value;
  427.             return Optional.of(collection.size());
  428.         }
  429.         if (value instanceof Map) {
  430.             final var map = (Map<?, ?>) value;
  431.             return Optional.of(map.size());
  432.         }
  433.         if (value instanceof String) {
  434.             try {
  435.                 return callback.apply((String) value);
  436.             } catch (final NumberFormatException ignored) {
  437.                 return Optional.empty();
  438.             }
  439.         }
  440.     }
  441.  
  442.     private NumberType(Class<N> clazz, Function<String, N> callback) {
  443.         super(Integer.class);
  444.         this.callback = callback;
  445.     }
  446.  
  447. }
  448.  
  449. public class StringType extends ClassType<String> {
  450.  
  451.     public static final StringType STRING = new StringType();
  452.  
  453.     @NonNull @Override
  454.     protected Optional<Object> doConversion(@Nullable Object value, @NonNull Source source) {
  455.         if (value == null || value == JSONObject.NULL) {
  456.             return Optional.empty();
  457.         }
  458.         return Optional.of(value.toString());
  459.     }
  460.  
  461.     private StringType() {
  462.         super(String.class);
  463.     }
  464.  
  465. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top