Skip to content

Commit 3bcc855

Browse files
hansonrhansonr
authored andcommitted
JAXB marshaller/unmarshaller for List<Object>, Map<Object,Object>
1 parent e399cd9 commit 3bcc855

File tree

6 files changed

+120
-71
lines changed

6 files changed

+120
-71
lines changed

sources/net.sf.j2s.java.core/src/swingjs/xml/JSJAXBClass.java

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,17 @@ class JSJAXBClass {
3131
private Map<String, JSJAXBField> fieldMap = new Hashtable<String, JSJAXBField>();
3232

3333
boolean isAnonymous;
34+
boolean isXmlIDREF;
35+
3436
JSJAXBField field;
3537
QName qualifiedTypeName;
3638

37-
JSJAXBField valueField;
39+
JSJAXBField xmlValueField, xmlIDField;
40+
3841

39-
JSJAXBClass(Class<?> javaClass, Object javaObject) {
40-
checkC$__ANN__(this, javaClass, javaObject);
42+
JSJAXBClass(Class<?> javaClass, Object javaObject, boolean isXmlIDREF) {
43+
checkC$__ANN__(this, javaClass, javaObject, isXmlIDREF);
44+
this.isXmlIDREF = isXmlIDREF;
4145
}
4246

4347
/**
@@ -48,7 +52,7 @@ class JSJAXBClass {
4852
* @return
4953
*/
5054
@SuppressWarnings("unused")
51-
private static boolean checkC$__ANN__(JSJAXBClass jsjaxbClass, Class<?> javaClass, Object javaObject) {
55+
private static boolean checkC$__ANN__(JSJAXBClass jsjaxbClass, Class<?> javaClass, Object javaObject, boolean isXmlIDREF) {
5256
boolean isTop = true;
5357
while (javaClass != null) {
5458

@@ -57,15 +61,12 @@ class JSJAXBClass {
5761
// ['cb','String',['@XmlAttribute(namespace="www.jalview.org2")']],
5862
// ['bytes','[array]',['@XmlAttribute']]];
5963

60-
Object clazz = (/** @j2sNative javaClass.$clazz$ || */
61-
null);
64+
Object clazz = (/** @j2sNative javaClass.$clazz$ || */ null);
6265
if (clazz == null)
6366
break;
64-
Object[][][] jsdata = (/** @j2sNative clazz.__ANN__ || */
65-
null);
66-
String className = (/** @j2sNative clazz.__CLASS$NAME__ || clazz.__CLASS_NAME__ || */
67-
null);
68-
67+
Object[][][] jsdata = (/** @j2sNative clazz.__ANN__ || */ null);
68+
String className = (/** @j2sNative clazz.__CLASS$NAME__ || clazz.__CLASS_NAME__ || */ null);
69+
6970
if (!isTop) {
7071
className = null;
7172
}
@@ -83,9 +84,8 @@ class JSJAXBClass {
8384
JSJAXBClass addTypeData(Object[][][] jsdata, String className, Object javaObject) {
8485
for (int i = 0; i < jsdata.length; i++) {
8586
JSJAXBField field = new JSJAXBField(this, jsdata[i], javaObject, fields.size(), propOrder);
86-
addField(field);
87+
addField(field);
8788
}
88-
8989
for (int i = propOrder.size(); --i >= 0;) {
9090
String prop = propOrder.get(i);
9191
JSJAXBField field = fieldMap.get(prop);
@@ -95,7 +95,7 @@ JSJAXBClass addTypeData(Object[][][] jsdata, String className, Object javaObject
9595
new Object[][] { new Object[] { prop, null, null, null }, new Object[] { "@XmlElement" } },
9696
javaObject, fields.size(), null));
9797
}
98-
}
98+
}
9999
return this;
100100
}
101101

@@ -105,7 +105,7 @@ private void addField(JSJAXBField field) {
105105
fieldMap.put(field.javaName, field);
106106
}
107107

108-
JSJAXBField getFieldFromJavaName(String javaName) {
108+
JSJAXBField getFieldFromJavaNameForMarshaller(String javaName) {
109109
return fieldMap.get(javaName);
110110
}
111111

@@ -116,7 +116,6 @@ static String getXmlNameFromClassName(String className) {
116116
return className;
117117
}
118118

119-
final static Map<String, JSJAXBField> bindingMap = new Hashtable<String, JSJAXBField>();
120119
// private static boolean hasNull(Object[] list) {
121120
// for (int i = list.length; --i >= 0;)
122121
// if (list[i] == null)
@@ -131,48 +130,61 @@ static String getXmlNameFromClassName(String className) {
131130
// return false;
132131
// }
133132
//
134-
public String defaultNamespace;
133+
String defaultNamespace;
135134
private String[] seeAlso;
135+
final Map<String, JSJAXBField> bindingMap = new Hashtable<String, JSJAXBField>();
136+
final static Map<String, JSJAXBField> seeAlsoMap = new Hashtable<String, JSJAXBField>();
136137

137138
void prepareForUnmarshalling(String defaultNamespace) {
138139
this.defaultNamespace = defaultNamespace;
139140
if (seeAlso != null) {
140141
for (int i = 0; i < seeAlso.length; i++) {
141142
try {
142-
JSJAXBClass jaxbClass = new JSJAXBClass(Class.forName(seeAlso[i]), null);
143-
bindQNamesForField(jaxbClass.fields.get(0));
143+
Class<?> cl = Class.forName(seeAlso[i]);
144+
addSeeAlso(cl);
144145
System.out.println("JSJAXBClass seeAlso: " + seeAlso[i]);
145146
} catch (ClassNotFoundException e) {
146147
System.out.println("JSJAXBClass[" + i + "] not found: " + seeAlso[i]);
147148
}
148149
}
149150
}
150151
for (int i = 0; i < fields.size(); i++) {
151-
bindQNamesForField(fields.get(i));
152+
JSJAXBField field = fields.get(i);
153+
bindQName(bindingMap, field.qualifiedName, field);
154+
bindQName(bindingMap, field.qualifiedWrapName, field);
155+
bindQName(bindingMap, field.qualifiedTypeName, field);
152156
}
153157
}
154158

155-
private void bindQNamesForField(JSJAXBField field) {
156-
bindQName(field.qualifiedName, field);
157-
bindQName(field.qualifiedWrapName, field);
158-
bindQName(field.qualifiedTypeName, field);
159+
void addSeeAlso(Class<?> cl) {
160+
JSJAXBClass jaxbClass = new JSJAXBClass(cl, null, false);
161+
JSJAXBField field = jaxbClass.fields.get(0);
162+
bindQName(seeAlsoMap, field.qualifiedName, field);
163+
bindQName(seeAlsoMap, field.qualifiedWrapName, field);
164+
bindQName(seeAlsoMap, field.qualifiedTypeName, field);
159165
}
160-
161-
private void bindQName(QName q, JSJAXBField field) {
166+
167+
private void bindQName(Map<String, JSJAXBField> map, QName q, JSJAXBField field) {
162168
if (q == null)
163169
return;
164-
bindingMap.put(q.getLocalPart(), field);
170+
map.put(q.getLocalPart(), field);
165171
String namespace = q.getNamespaceURI();
166172
if (namespace.length() == 0)
167173
namespace = defaultNamespace;
168174
if (namespace != null)
169-
bindingMap.put(namespace + ":" + q.getLocalPart(), field);
175+
map.put(namespace + ":" + q.getLocalPart(), field);
170176
//System.out.println("JSJAXBClass#binding " + namespace + ":" + q.getLocalPart() + "->" + field.javaName);
171177
}
172178

173179
JSJAXBField getFieldFromQName(QName qName) {
174180
String key = qName.getNamespaceURI() + ":" + qName.getLocalPart();
175181
JSJAXBField f = bindingMap.get(key);
182+
if (f == null)
183+
f = bindingMap.get(qName.getLocalPart());
184+
if (f == null)
185+
f = seeAlsoMap.get(key);
186+
if (f == null)
187+
f = seeAlsoMap.get(qName.getLocalPart());
176188
return f;
177189
}
178190

@@ -201,7 +213,7 @@ static boolean isMarshallable(JSJAXBField field) {
201213
try {
202214
if (classMap.containsKey(javaClassName))
203215
return classMap.get(javaClassName).booleanValue();
204-
isMarshallable = (checkC$__ANN__(null, Class.forName(javaClassName), null));
216+
isMarshallable = (checkC$__ANN__(null, Class.forName(javaClassName), null, false));
205217
} catch (ClassNotFoundException e) {
206218
System.out.println("JSJAXBClass: class was not found: " + javaClassName);
207219
e.printStackTrace();
@@ -213,11 +225,11 @@ static boolean isMarshallable(JSJAXBField field) {
213225

214226
static Map<String, JSJAXBClass> knownClasses = new Hashtable<>();
215227

216-
static JSJAXBClass newInstance(Class<?> javaClass, Object javaObject) {
228+
static JSJAXBClass newUnmarshalledInstance(Class<?> javaClass, Object javaObject) {
217229
String name = javaClass.getCanonicalName();
218230
JSJAXBClass jjc = knownClasses.get(name);
219231
if (jjc == null) {
220-
jjc = new JSJAXBClass(javaClass, javaObject);
232+
jjc = new JSJAXBClass(javaClass, javaObject, false);
221233
knownClasses.put(name, jjc);
222234
return jjc;
223235
}

sources/net.sf.j2s.java.core/src/swingjs/xml/JSJAXBField.java

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,9 @@ void setNode(DOMNode node) {
8787
String javaClassName;
8888

8989
boolean isAttribute;
90-
boolean isID;
91-
boolean isIDREF;
92-
boolean isValue;
90+
boolean isXmlID;
91+
boolean isXmlIDREF;
92+
boolean isXmlValue;
9393
boolean asList;
9494
boolean isNillable;
9595
boolean isArray;
@@ -301,9 +301,10 @@ else if (data.indexOf("PROPERTY") >= 0)
301301
break;
302302
case "@XmlSeeAlso":
303303
// @XmlSeeAlso({Dog.class,Cat.class})
304-
// class Animal {}
305-
// class Dog extends Animal {}
306-
// class Cat extends Animal {}
304+
// allows these classes to be identified even though not
305+
// part of the context of the given class, for example
306+
// an instance-only class referenced by this class, as
307+
// in an Object, Object[], List<Object>, or Map<Object,Object>
307308
jaxbClass.setSeeAlso(getSeeAlso(data));
308309
break;
309310
case "@XmlAttribute":
@@ -314,10 +315,6 @@ else if (data.indexOf("PROPERTY") >= 0)
314315
qualifiedName = getName(tag);
315316
isNillable = "true".equals(attr.get("@XmlElement:nillable"));
316317
break;
317-
case "@XmlValue":
318-
jaxbClass.valueField = this;
319-
isValue = true;
320-
break;
321318
case "@XmlSchemaType":
322319
xmlSchema = attr.get("@XmlSchemaType:name");
323320
if (xmlSchema.equals("hexBinary")) {
@@ -343,10 +340,15 @@ else if (data.indexOf("PROPERTY") >= 0)
343340
typeAdapter = typeAdapter.substring(0, data.length() - 6);
344341
break;
345342
case "@XmlID":
346-
isID = true;
343+
isXmlID = true;
344+
jaxbClass.xmlIDField = this;
345+
break;
346+
case "@XmlValue":
347+
jaxbClass.xmlValueField = this;
348+
isXmlValue = true;
347349
break;
348350
case "@XmlIDREF":
349-
isIDREF = true;
351+
isXmlIDREF = true;
350352
break;
351353
case "@XmlList":
352354
asList = true;

sources/net.sf.j2s.java.core/src/swingjs/xml/JSJAXBMarshaller.java

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ public void marshal(Object jaxbElement, Result result) throws JAXBException {
7171
private void doMarshal(Class<?> javaClass, Object javaObject, JSJAXBField field, boolean addXsiType) throws JAXBException {
7272
// at least for now we rely on fields that are designated.
7373

74-
JSJAXBClass jaxbClass = new JSJAXBClass(javaClass, javaObject);
74+
JSJAXBClass jaxbClass = new JSJAXBClass(javaClass, javaObject, field != null && field.isXmlIDREF);
7575
jaxbClass.field = field;
76-
76+
7777
Map<String, Integer> oldMap = null;
7878
if (field == null) {
7979
clearQualifierMap();
@@ -137,7 +137,7 @@ private static boolean isArray(Object value) {
137137
}
138138

139139
private static JSJAXBField getField(JSJAXBClass jaxbClass, String javaName) {
140-
return jaxbClass.getFieldFromJavaName(javaName);
140+
return jaxbClass.getFieldFromJavaNameForMarshaller(javaName);
141141
}
142142

143143
private static DOMNode textarea;
@@ -185,13 +185,18 @@ private void writeXML(JSJAXBClass jaxbClass, boolean isRoot, boolean addXsiType)
185185
if (isRoot)
186186
addDefaultNameSpace();
187187
addAllNameSpaces(jaxbClass);
188-
addFields(jaxbClass, true);
188+
if (!jaxbClass.isXmlIDREF)
189+
addFields(jaxbClass, true);
189190
if (!jaxbClass.hasElements()) {
190191
output(" />");
191192
return;
192193
}
193194
output(">");
194-
addFields(jaxbClass, false);
195+
if (jaxbClass.isXmlIDREF) {
196+
writeValue(jaxbClass.xmlIDField, jaxbClass.xmlIDField.getValue());
197+
} else {
198+
addFields(jaxbClass, false);
199+
}
195200
if (isRoot)
196201
output("\n");
197202
writeTagClose(qname, !isRoot);
@@ -214,8 +219,7 @@ private void addAllNameSpaces(JSJAXBClass jaxbClass) throws JAXBException {
214219

215220
private void addFields(JSJAXBClass jaxbClass, boolean isAttribute) throws JAXBException {
216221
// no ordering for attributes -- they must be designated explicitly
217-
JSJAXBField field;
218-
if (jaxbClass.propOrder.size() == 0 || isAttribute) {
222+
JSJAXBField field;if (jaxbClass.propOrder.size() == 0 || isAttribute) {
219223
for (int i = 0, n = jaxbClass.fields.size(); i < n; i++)
220224
if (isAttribute == (field = jaxbClass.fields.get(i)).isAttribute)
221225
addField(field);
@@ -257,7 +261,7 @@ private void addFieldListable(JSJAXBField field, Object value, boolean addXsiTyp
257261
private void writeField(JSJAXBField field, Object value, boolean addXsiType) throws JAXBException {
258262
if (field.isAttribute) {
259263
writeAttribute(field, value);
260-
} else if (field.isValue) {
264+
} else if (field.isXmlValue) {
261265
writeValue(field, value);
262266
} else {
263267
writeTagOpen(field.qualifiedName, true);
@@ -423,7 +427,7 @@ private void writeFieldArray(JSJAXBField field, Object values) throws JAXBExcept
423427
if (wrapName != null) {
424428
writeTagOpen(wrapName, true);
425429
output(">");
426-
} else if (isEmpty && !isNillable) {
430+
} else if (isEmpty && !isNillable) {
427431
return;
428432
}
429433
for (int i = 0, pt = 0, n = list.length; i < n; i++) {

sources/net.sf.j2s.java.core/src/swingjs/xml/JSJAXBUnmarshaller.java

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,12 @@ private Object doUnmarshal(DOMNode node, Class<?> javaClass) {
105105
e.printStackTrace();
106106
return null;
107107
}
108-
108+
if (jaxbClass != null)
109+
jaxbClass.addSeeAlso(javaClass);
109110
JSJAXBClass oldJaxbClass = jaxbClass;
110111
DOMNode oldDoc = doc;
111112
doc = null;
112-
jaxbClass = JSJAXBClass.newInstance(javaClass, javaObject);
113+
jaxbClass = JSJAXBClass.newUnmarshalledInstance(javaClass, javaObject);
113114
boolean topOnly = true;
114115
try {
115116
parser.setContentHandler(this);
@@ -236,7 +237,12 @@ private Object getNodeObject(DOMNode node, String definedType, Object data, bool
236237
return null;
237238
if (type.indexOf(":") >= 0 && !type.startsWith("xs:")) {
238239
// this is a SeeAlso entry
239-
return unmarshalField(jaxbClass.getFieldFromQName(getQnameForAttribute(null, null, type)), node);
240+
QName qname = getQnameForAttribute(null, null, type);
241+
JSJAXBField field = jaxbClass.getFieldFromQName(qname);
242+
243+
244+
245+
return unmarshalField(field, node);
240246
}
241247
return convertFromType(null, data, type, asObject);
242248
}
@@ -255,15 +261,15 @@ private void start(DOMNode node, QName qName, Attributes atts) {
255261
}
256262

257263
private void setDocAttributes(String value, Attributes atts) {
258-
if (jaxbClass.valueField != null) {
259-
jaxbClass.valueField.setCharacters(value);
260-
jaxbClass.valueField.setNode(doc);
261-
setFieldValue(jaxbClass.valueField);
264+
if (jaxbClass.xmlValueField != null) {
265+
jaxbClass.xmlValueField.setCharacters(value);
266+
jaxbClass.xmlValueField.setNode(doc);
267+
setFieldValue(jaxbClass.xmlValueField);
262268
}
263269
jaxbClass.prepareForUnmarshalling(atts.getValue("xmlns"));
264270
for (int i = atts.getLength(); --i >= 0;) {
265271
String uri = atts.getURI(i);
266-
String localName = atts.getURI(i);
272+
String localName = atts.getLocalName(i);
267273
String qname = atts.getQName(i);
268274
if (qname.equals("xmlns") || qname.startsWith("xmlns:")) {
269275
continue;

sources/net.sf.j2s.java.core/src/test/Test_JAXB_ORDERED.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import javax.xml.datatype.XMLGregorianCalendar;
1616

1717
import test.jaxb.Root_ORDERED;
18+
import test.jaxb.Root_ORDERED.SomewhatComplex;
1819

1920
@XmlRegistry
2021
public class Test_JAXB_ORDERED extends Test_ {
@@ -31,6 +32,9 @@ public static void main(String[] args) {
3132
Root_ORDERED root = new Root_ORDERED();
3233
root.f5[0] = 1.25f;
3334
root.f5[1] = new test.jaxb.Obj();
35+
((SomewhatComplex)root.cx).bytes[0] = 99;
36+
((SomewhatComplex)root.cx).id = "#??";
37+
3438
root.setCreationDate(now());
3539
Marshaller marshaller = jc.createMarshaller();
3640
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
@@ -48,6 +52,8 @@ public static void main(String[] args) {
4852
System.out.println(r.getCreationDate());
4953
System.out.println(r.f5[0]);
5054
System.out.println(((test.jaxb.Obj) r.f5[1]).obj1);
55+
System.out.println(((SomewhatComplex)r.cx).bytes[0]);
56+
System.out.println(((SomewhatComplex)r.cx).id);
5157
} catch (UnsupportedEncodingException e) {
5258
e.printStackTrace();
5359
}

0 commit comments

Comments
 (0)