1 package be
.nikiroo
.utils
.serial
;
3 import java
.lang
.reflect
.Constructor
;
4 import java
.lang
.reflect
.Field
;
5 import java
.lang
.reflect
.InvocationTargetException
;
6 import java
.util
.HashMap
;
8 import java
.util
.Scanner
;
10 import be
.nikiroo
.utils
.IOUtils
;
11 import be
.nikiroo
.utils
.StringUtils
;
14 * A simple class that can accept the output of {@link Exporter} to recreate
15 * objects as they were sent to said exporter.
17 * This class requires the objects (and their potential enclosing objects) to
18 * have an empty constructor, and does not support inner classes (it does
19 * support nested classes, though).
23 public class Importer
{
26 private Importer child
;
27 private Map
<String
, Object
> map
;
29 private String currentFieldName
;
32 map
= new HashMap
<String
, Object
>();
33 map
.put("NULL", null);
36 private Importer(Map
<String
, Object
> map
) {
40 public Importer
readLine(String line
) {
43 } catch (Exception e
) {
44 throw new IllegalArgumentException(e
);
49 public Importer
read(String data
) {
51 if (data
.startsWith("ZIP:")) {
52 data
= StringUtils
.unzip64(data
.substring("ZIP:".length()));
54 Scanner scan
= new Scanner(data
);
55 scan
.useDelimiter("\n");
56 while (scan
.hasNext()) {
57 processLine(scan
.next());
60 } catch (Exception e
) {
61 throw new IllegalArgumentException(e
);
66 public boolean processLine(String line
) throws IllegalArgumentException
,
67 NoSuchFieldException
, SecurityException
, IllegalAccessException
,
68 NoSuchMethodException
, InstantiationException
, ClassNotFoundException
, InvocationTargetException
{
69 // Defer to latest child if any
71 if (child
.processLine(line
)) {
72 if (currentFieldName
!= null) {
73 setField(currentFieldName
, child
.getValue());
74 currentFieldName
= null;
82 if (line
.equals("{")) { // START: new child if needed
84 child
= new Importer(map
);
86 } else if (line
.equals("}")) { // STOP: report self to parent
88 } else if (line
.startsWith("REF ")) { // REF: create/link self
89 String ref
= line
.substring(4).split("@")[1];
90 link
= map
.containsKey(ref
);
94 me
= createSelf(line
.substring(4).split("@")[0]);
97 } else { // FIELD: new field
98 if (line
.endsWith(":")) {
99 // field value is compound
100 currentFieldName
= line
.substring(0, line
.length() - 1);
102 // field value is direct
103 int pos
= line
.indexOf(":");
104 String fieldName
= line
.substring(0, pos
);
105 String encodedValue
= line
.substring(pos
+ 1);
107 value
= SerialUtils
.decode(encodedValue
);
109 // To support simple types directly:
113 setField(fieldName
, value
);
122 * Create an empty object of the given type.
128 * @throws NoSuchMethodException
129 * @throws SecurityException
130 * @throws InstantiationException
131 * @throws IllegalAccessException
132 * @throws ClassNotFoundException
133 * @throws IllegalArgumentException
134 * @throws InvocationTargetException
136 private Object
createSelf(String type
) throws NoSuchMethodException
,
137 SecurityException
, InstantiationException
, IllegalAccessException
,
138 ClassNotFoundException
, IllegalArgumentException
,
139 InvocationTargetException
{
142 Class
<?
> clazz
= getClass(type
);
144 throw new ClassNotFoundException("Class not found: " + type
);
147 String className
= clazz
.getName();
148 Object
[] args
= null;
149 Constructor
<?
> ctor
= null;
150 if (className
.contains("$")) {
151 Object javaParent
= createSelf(className
.substring(0,
152 className
.lastIndexOf('$')));
153 args
= new Object
[] { javaParent
};
154 ctor
= clazz
.getDeclaredConstructor(new Class
[] { javaParent
157 args
= new Object
[] {};
158 ctor
= clazz
.getDeclaredConstructor();
161 ctor
.setAccessible(true);
162 return ctor
.newInstance(args
);
163 } catch (NoSuchMethodException e
) {
164 throw new NoSuchMethodException(
166 "Objects of type \"%s\" cannot be created by this code: maybe the class"
167 + " or its enclosing class doesn't have an empty constructor?",
173 private Class
<?
> getClass(String type
) throws ClassNotFoundException
,
174 NoSuchMethodException
{
175 Class
<?
> clazz
= null;
177 clazz
= Class
.forName(type
);
178 } catch (ClassNotFoundException e
) {
179 int pos
= type
.length();
180 pos
= type
.lastIndexOf(".", pos
);
182 String parentType
= type
.substring(0, pos
);
183 String nestedType
= type
.substring(pos
+ 1);
184 Class
<?
> javaParent
= null;
186 javaParent
= getClass(parentType
);
187 parentType
= javaParent
.getName();
188 clazz
= Class
.forName(parentType
+ "$" + nestedType
);
189 } catch (Exception ee
) {
192 if (javaParent
== null) {
193 throw new NoSuchMethodException(
196 + " (the enclosing class cannot be created: maybe it doesn't have an empty constructor?)");
204 private void setField(String name
, Object value
)
205 throws NoSuchFieldException
, SecurityException
,
206 IllegalArgumentException
, IllegalAccessException
{
209 Field field
= me
.getClass().getDeclaredField(name
);
211 field
.setAccessible(true);
212 field
.set(me
, value
);
213 } catch (NoSuchFieldException e
) {
214 throw new NoSuchFieldException(String
.format(
215 "Field \"%s\" was not found in object of type \"%s\".",
216 name
, me
.getClass().getCanonicalName()));
220 public Object
getValue() {