/
AnnotationBasedJsonParsable.java
112 lines (98 loc) · 4.2 KB
/
AnnotationBasedJsonParsable.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/*
* Copyright (c) 2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.ditto.signals.base;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.eclipse.ditto.json.JsonObject;
import org.eclipse.ditto.json.JsonParseException;
import org.eclipse.ditto.model.base.exceptions.DittoJsonException;
import org.eclipse.ditto.model.base.exceptions.DittoRuntimeException;
import org.eclipse.ditto.model.base.headers.DittoHeaders;
/**
* Responsible for deserialization of a class of type T.
*
* @param <T> the type of the class that should be deserialized.
*/
final class AnnotationBasedJsonParsable<T> implements JsonParsable<T> {
private static final Class<?> JSON_OBJECT_PARAMETER = JsonObject.class;
private static final Class<?> DITTO_HEADERS_PARAMETER = DittoHeaders.class;
private final String key;
private final String v1FallbackKey;
private final Method parseMethod;
/**
* Creates a new instance.
*
* @param key the API v2 key for this strategy.
* @param v1FallbackKey the API v1 key for this strategy.
* @param parsedClass the class that should be deserialized.
* @param parsingMethodName the name of the method that should be called on the given class in order to
* deserialize.
*/
AnnotationBasedJsonParsable(final String key, final String v1FallbackKey,
final Class<? extends T> parsedClass,
final String parsingMethodName) {
this.key = key;
this.v1FallbackKey = v1FallbackKey;
try {
this.parseMethod =
parsedClass.getMethod(parsingMethodName, JSON_OBJECT_PARAMETER, DITTO_HEADERS_PARAMETER);
final Class<?> returnType = parseMethod.getReturnType();
if (!parsedClass.isAssignableFrom(returnType)) {
throw new IllegalArgumentException(
String.format("Parse method is invalid. Return type <%s> of parse method must be assignable " +
"to parsed class: <%s>.", returnType.getSimpleName(), parsedClass.getSimpleName()));
}
} catch (final NoSuchMethodException e) {
throw new DeserializationStrategyNotFoundError(parsedClass, e);
}
}
/**
* The API v2 key for this strategy.
*
* @return the API v2 key for this strategy.
*/
public String getKey() {
return key;
}
/**
* The API v1 key for this strategy.
*
* @return the API v1 key for this strategy.
*/
public String getV1FallbackKey() {
return v1FallbackKey;
}
@SuppressWarnings("unchecked") //suppressed because returned type is ensured in constructor
@Override
public T parse(final JsonObject jsonObject, final DittoHeaders dittoHeaders) {
try {
return (T) parseMethod.invoke(null, jsonObject, dittoHeaders);
} catch (final ClassCastException | IllegalAccessException e) {
throw buildDittoJsonException(e, jsonObject, dittoHeaders);
} catch (final InvocationTargetException e) {
final Throwable targetException = e.getTargetException();
if (targetException instanceof DittoRuntimeException) {
throw (DittoRuntimeException) targetException;
}
throw buildDittoJsonException(targetException, jsonObject, dittoHeaders);
}
}
private DittoJsonException buildDittoJsonException(final Throwable cause,
final JsonObject jsonObject,
final DittoHeaders dittoHeaders) {
return new DittoJsonException(JsonParseException.newBuilder()
.message(String.format("Error during parsing json: <%s>", jsonObject.toString()))
.cause(cause).build(),
dittoHeaders);
}
}