-
-
Notifications
You must be signed in to change notification settings - Fork 70
/
TypeConverter.java
241 lines (208 loc) · 8.25 KB
/
TypeConverter.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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
package org.freedesktop.dbus.utils.generator;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;
import org.freedesktop.dbus.Marshalling;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.dbus.types.DBusListType;
import org.freedesktop.dbus.types.DBusMapType;
import org.freedesktop.dbus.types.Variant;
import com.github.hypfvieh.util.StringUtil;
/**
* Helper to convert DBus types and java types.
*
* @author hypfvieh
* @since v3.0.1 - 2018-12-22
*/
public class TypeConverter {
private static final Map<String, String> CLASS_MAP = new HashMap<>();
static {
CLASS_MAP.put("java.lang.CharSequence", "String");
CLASS_MAP.put("java.util.List", "List");
CLASS_MAP.put("java.util.Set", "Set");
CLASS_MAP.put("java.util.Map", "Map");
CLASS_MAP.put(Variant.class.getName(), "Variant<?>");
}
/**
* Converts a java class type to another type.
* This is used for converting e.g. CharSequence to String etc.
* It will also remove unnecessary package names like java.lang.
*
* @param _argType Argument to convert
* @param _includes Set where additional includes will be added (should never be null!)
* @return String with proper type, if no converation could be done, original input is returned
*/
public static String getProperJavaClass(String _argType, Set<String> _includes) {
String clazzName = null;
if (_argType == null) {
return _argType;
}
// this is something with generics, so we do not convert boxed type to primitives
if (_argType.contains("<")) {
clazzName = _argType;
for (Entry<String, String> clzzNames : CLASS_MAP.entrySet()) {
if (clazzName.contains(clzzNames.getKey())) {
clazzName = clazzName.replace(clzzNames.getKey(), clzzNames.getValue());
if (!clzzNames.getKey().startsWith("java.lang.")) { // only add imports for classes not in java.lang (which is always in scope)
_includes.add(clzzNames.getKey());
}
}
}
clazzName = clazzName.replace("java.lang.", "");
} else {
clazzName = _argType.substring(_argType.lastIndexOf(".") + 1);
// change some boxed types back to primitives
return convertJavaType(clazzName, true);
}
return clazzName;
}
/**
* Transform certain java types to other java types (see {@link #CLASS_MAP}).
*
* @param _fqcn fully qualified classname of the type to convert
* @param _usePrimitives if true, boxed types will be converted to primitives
* @return converted type or original input
*/
private static String convertJavaType(String _fqcn, boolean _usePrimitives) {
if (_fqcn == null) {
return _fqcn;
}
String clazzName = _fqcn;
if (_fqcn.contains(".")) {
clazzName = _fqcn.substring(_fqcn.lastIndexOf(".") + 1);
}
if (CLASS_MAP.containsKey(_fqcn)) {
return CLASS_MAP.get(_fqcn);
}
if (clazzName.equals("CharSequence")) {
return "String";
}
return _usePrimitives ? convertJavaBoxedTypeToPrimitive(clazzName) : clazzName;
}
/**
* Converts certain boxed types to primitives.
*
* @param _clazzName class name of boxed type
* @return primitive or original input
*/
private static String convertJavaBoxedTypeToPrimitive(String _clazzName) {
switch (_clazzName) {
case "Boolean":
return "boolean";
case "Integer":
return "int";
case "Long":
return "long";
case "Double":
return "double";
case "Float":
return "float";
case "Byte":
return "byte";
case "Char":
return "char";
default:
return _clazzName;
}
}
/**
* Converts a DBus data type string to java classname(s).
*
* @param _dbusType DBus data type string
* @param _javaIncludes List where additional imports will be added to (should not be null!)
* @return Java classname, maybe null if no suitable input was given
*
* @throws DBusException on DBus error
*/
public static String getJavaTypeFromDBusType(String _dbusType, Set<String> _javaIncludes) throws DBusException {
List<Type> dataType = new ArrayList<>();
String type;
if (StringUtil.isBlank(_dbusType)) {
return null;
}
if (_dbusType.length() == 1) {
Marshalling.getJavaType(_dbusType, dataType, 1);
type = dataType.stream()
.map(t -> {
return t.getTypeName();
})
.collect(Collectors.joining(""));
_javaIncludes.add(type);
} else {
type = getTypeAdv(_dbusType, _javaIncludes);
}
return type;
}
/**
* Resolve java type recursively.
*
* @param _type Type object
* @param _innerGenerics list which will be populated with classnames of the inner generic types (if any)
* @return Map where key is parent classname (e.g. List) and value is a list of types used inside the generics
*
* @throws DBusException on error
*/
private static Map<String, List<String>> getTypeAdv(Type _type, List<String> _innerGenerics) throws DBusException {
Map<String, List<String>> result = new LinkedHashMap<>();
if (_type instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType) _type;
List<String> generics = new ArrayList<>();
result.put(pType.getRawType().getTypeName(), generics);
for (Type t : pType.getActualTypeArguments()) {
if (t instanceof ParameterizedType) {
result.putAll(getTypeAdv(t, generics));
} else {
generics.add(t.getTypeName());
}
}
} else {
result.put(_type.getTypeName(), new ArrayList<>());
}
return result;
}
/**
* Special handling for {@link DBusMapType} and {@link DBusListType}.
*
* @param _dbusType DBus type string
* @param _javaIncludes list where additional java imports are added to (if any)
* @return class name of the parent type, maybe null if no suitable input provided
*
* @throws DBusException
*/
private static String getTypeAdv(String _dbusType, Set<String> _javaIncludes) throws DBusException {
if (StringUtil.isBlank(_dbusType)) {
return null;
}
List<Type> dataType = new ArrayList<>();
Marshalling.getJavaType(_dbusType, dataType, 1);
if (dataType.get(0) instanceof DBusListType || dataType.get(0) instanceof DBusMapType) {
ParameterizedType dBusListType = (ParameterizedType) dataType.get(0);
Type[] actualTypeArguments = dBusListType.getActualTypeArguments();
String actualArgTypeVal = "?";
String retVal = dBusListType.getRawType().getTypeName();
if (actualTypeArguments.length > 0) {
Map<String, List<String>> typeAdv = getTypeAdv(actualTypeArguments[0], null);
actualArgTypeVal = "";
for (Entry<String, List<String>> e : typeAdv.entrySet()) {
if (!e.getValue().isEmpty()) {
actualArgTypeVal += e.getKey() + "<";
actualArgTypeVal += String.join(", ", e.getValue());
actualArgTypeVal += ">";
_javaIncludes.addAll(e.getValue());
} else {
actualArgTypeVal = e.getKey();
}
}
}
return retVal + "<" + actualArgTypeVal + ">";
}
return dataType.get(0).getTypeName();
}
}