Skip to contentMethod: lambda$initTransformers$4(Object)
1: /**
2: * Copyright (C) 2020 Czech Technical University in Prague
3: * <p>
4: * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
5: * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
6: * version.
7: * <p>
8: * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
9: * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
10: * details. You should have received a copy of the GNU General Public License along with this program. If not, see
11: * <http://www.gnu.org/licenses/>.
12: */
13: package cz.cvut.kbss.jopa.utils;
14:
15: import cz.cvut.kbss.jopa.exception.UnsupportedTypeTransformation;
16: import cz.cvut.kbss.jopa.exceptions.OWLPersistenceException;
17: import cz.cvut.kbss.ontodriver.model.LangString;
18:
19: import java.lang.reflect.Constructor;
20: import java.lang.reflect.InvocationTargetException;
21: import java.net.MalformedURLException;
22: import java.net.URI;
23: import java.net.URL;
24: import java.util.HashMap;
25: import java.util.Map;
26: import java.util.Optional;
27: import java.util.function.Function;
28:
29: /**
30: * Utility containing some basic mappings for conversion between types.
31: */
32: public class DatatypeTransformer {
33:
34: private static final Map<Pair, Function<Object, ?>> TRANSFORMERS = initTransformers();
35:
36: private DatatypeTransformer() {
37: throw new AssertionError();
38: }
39:
40: private static Map<Pair, Function<Object, ?>> initTransformers() {
41: final Map<Pair, Function<Object, ?>> map = new HashMap<>();
42: map.put(new Pair(Short.class, Integer.class), value -> ((Short) value).intValue());
43: map.put(new Pair(Short.class, Long.class), value -> ((Short) value).longValue());
44: map.put(new Pair(Short.class, Float.class), value -> ((Short) value).floatValue());
45: map.put(new Pair(Short.class, Double.class), value -> ((Short) value).doubleValue());
46: map.put(new Pair(Integer.class, Short.class), value -> ((Integer) value).shortValue());
47: map.put(new Pair(Integer.class, Long.class), value -> ((Integer) value).longValue());
48: map.put(new Pair(Integer.class, Float.class), value -> ((Integer) value).doubleValue());
49: map.put(new Pair(Integer.class, Double.class), value -> ((Integer) value).doubleValue());
50: map.put(new Pair(Long.class, Integer.class), value -> ((Long) value).intValue());
51: map.put(new Pair(Long.class, Short.class), value -> ((Long) value).shortValue());
52: map.put(new Pair(Long.class, Float.class), value -> ((Long) value).floatValue());
53: map.put(new Pair(Long.class, Double.class), value -> ((Long) value).doubleValue());
54: map.put(new Pair(Float.class, Short.class), value -> ((Float) value).shortValue());
55: map.put(new Pair(Float.class, Integer.class), value -> ((Float) value).intValue());
56: map.put(new Pair(Float.class, Long.class), value -> ((Float) value).longValue());
57: map.put(new Pair(Float.class, Double.class), value -> ((Float) value).doubleValue());
58: map.put(new Pair(Double.class, Short.class), value -> ((Double) value).shortValue());
59: map.put(new Pair(Double.class, Integer.class), value -> ((Double) value).intValue());
60: map.put(new Pair(Double.class, Long.class), value -> ((Double) value).longValue());
61: map.put(new Pair(Double.class, Float.class), value -> ((Double) value).floatValue());
62: map.put(new Pair(URI.class, URL.class), value -> {
63: try {
64: return ((URI) value).toURL();
65: } catch (MalformedURLException e) {
66: throw new OWLPersistenceException("Unable to transform URI to URL.", e);
67: }
68: });
69: return map;
70: }
71:
72: /**
73: * Maps the specified value to the target type (if possible).
74: *
75: * @param value The value to convert
76: * @param targetType The type to which the specified value should be converted
77: * @return Value as the target type
78: */
79: public static <T> T transform(Object value, Class<T> targetType) {
80: if (value == null) {
81: return null;
82: }
83: if (targetType.equals(String.class)) {
84: return targetType.cast(value instanceof LangString ? ((LangString) value).getValue() : value.toString());
85: }
86: final Class<?> sourceType = value.getClass();
87: if (targetType.isAssignableFrom(sourceType)) {
88: return targetType.cast(value);
89: }
90: final Pair p = new Pair(sourceType, targetType);
91: if (TRANSFORMERS.containsKey(p)) {
92: return targetType.cast(TRANSFORMERS.get(p).apply(value));
93: }
94: final Optional<T> result = tryConversionUsingConstructor(value, targetType);
95: return result.orElseThrow(() -> new UnsupportedTypeTransformation(
96: String.format("Cannot transform value %s of type %s to target type %s.", value, value.getClass(),
97: targetType)));
98: }
99:
100: private static <T> Optional<T> tryConversionUsingConstructor(Object value, Class<T> targetType) {
101: try {
102: final Constructor<T> ctor = targetType.getDeclaredConstructor(value.getClass());
103: return Optional.of(targetType.cast(ctor.newInstance(value)));
104: } catch (NoSuchMethodException e) {
105: return Optional.empty();
106: } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
107: throw new OWLPersistenceException("Unable to transform value using target type constructor.", e);
108: }
109: }
110:
111: private static final class Pair {
112:
113: private final Class<?> sourceType;
114: private final Class<?> targetType;
115:
116: private Pair(Class<?> sourceType, Class<?> targetType) {
117: this.sourceType = sourceType;
118: this.targetType = targetType;
119: }
120:
121: @Override
122: public boolean equals(Object o) {
123: if (this == o) {
124: return true;
125: }
126: if (!(o instanceof Pair)) {
127: return false;
128: }
129:
130: Pair pair = (Pair) o;
131:
132: return sourceType.equals(pair.sourceType) && targetType.equals(pair.targetType);
133: }
134:
135: @Override
136: public int hashCode() {
137: int result = sourceType.hashCode();
138: result = 31 * result + targetType.hashCode();
139: return result;
140: }
141: }
142: }