I am trying to create bean from string but unable to create as it is returning null.Here is my code
public ModelAndView checkPhotoQualityRequest(
#RequestBody String photoDataXml, HttpServletRequest request) {
PhotoQuality photoQuality = null;
try {
JAXBContext jaxbContext = JAXBContext
.newInstance(PhotoQuality.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader(photoDataXml);
photoQuality = (PhotoQuality) unmarshaller.unmarshal(reader);
PhotoQuality.java
package in.gov.uid.opencvaccess.bean;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlType(name = "PhotoQuality")
#XmlRootElement(name = "PhotoQuality")
public class PhotoQuality {
private String photoid;
private byte[] photo;
private boolean quality;
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getPhotoid() {
return photoid;
}
public void setPhotoid(String photoid) {
this.photoid = photoid;
}
public byte[] getPhoto() {
return photo;
}
public void setPhoto(byte[] photo) {
this.photo = photo;
}
public boolean isQuality() {
return quality;
}
public void setQuality(boolean quality) {
this.quality = quality;
}
}
Please help me to sort out this issue.When I debug and check bean its showing all null values but photoDataXml showing complete xml.
I have found the reason.When I tried using RESTClient its giving null object. But as soon as I written client code and passed StringWriter value created from PhotoQuality Object then it runs properly.
Related
I am working on a JavaFX application which facilitates all kind of sport related training sessions. Each session consists of multiple exercises, whereas each exercise is repeated multiple times in a few sets. I created some test data and marshalled it. As it turned out, some fields of the Exercise class objects were written but not all of them. By adding the #XmlElement(name="someTagName") tag to each getter of each field I managed that all fields are marshalled and the xml file looks like expected. However, when I unmarshall the xml file, only those fields, which were written without the #XmlElement tag are read and most of the fields only have the default value from the constructor. What am I missing in order to unmarshall all fields?
Here is the class that I want to marshall/unmarshall
package domain;
import jakarta.xml.bind.annotation.XmlAttribute;
import jakarta.xml.bind.annotation.XmlElement;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Exercise extends SelectableDomainObj {
protected StringProperty name;
protected StringProperty mediaFilePath;
protected IntegerProperty repsPerSet;
protected IntegerProperty numOfSets;
protected IntegerProperty breakBetweenSetsInSecs;
protected IntegerProperty displayTimeInSecs;
protected DoubleProperty startSpeed;
protected DoubleProperty endSpeed;
protected BooleanProperty withMetronom;
protected BooleanProperty showIntro;
/**
* Set some reasonable default values from lifting domain
*/
public Exercise() {
mediaFilePath = new SimpleStringProperty();
name = new SimpleStringProperty();
numOfSets = new SimpleIntegerProperty(3);
repsPerSet = new SimpleIntegerProperty(8);
breakBetweenSetsInSecs = new SimpleIntegerProperty(60);
displayTimeInSecs = new SimpleIntegerProperty(-1);
startSpeed = new SimpleDoubleProperty(1.0);
endSpeed = new SimpleDoubleProperty(1.0);
withMetronom = new SimpleBooleanProperty(false);
showIntro = new SimpleBooleanProperty(false);
}
#XmlElement(name="name")
public String getName() {
return name.get();
}
public void setName(String name) {
this.name.set(name);
}
public StringProperty nameProperty() {
return name;
}
#XmlElement(name="mediaFilePath")
public String getMediaFilePath() {
return mediaFilePath.get();
}
public void setMediaFilePath(String mediaFilePath) {
this.mediaFilePath.set(mediaFilePath);
}
public StringProperty mediaFilePathProperty() {
return mediaFilePath;
}
#XmlElement(name="repsPerSet")
public Integer getRepsPerSet() {
return repsPerSet.get();
}
public void setRepsPerSet(int repsPerSet) {
this.repsPerSet.set(repsPerSet);
}
public IntegerProperty repsPerSetProperty() {
return repsPerSet;
}
#XmlElement(name="numOfSets")
public int getNumOfSets() {
return numOfSets.get();
}
public void setNumOfSets(int numOfSets) {
this.numOfSets.set(numOfSets);
}
public IntegerProperty numOfSetsProperty() {
return numOfSets;
}
#XmlElement(name="breakBetweenSetsInSec")
public Integer getBreakBetweenSetsInSecs() {
return breakBetweenSetsInSecs.get();
}
public void setBreakBetweenSetsInSecs(int breakBetweenSetsInSecs) {
this.breakBetweenSetsInSecs.set(breakBetweenSetsInSecs);
}
public IntegerProperty displayTimeInSecsProperty() {
return displayTimeInSecs;
}
#XmlElement(name="displayTimeInSecs")
public Integer getDisplayTimeInSecs() {
return displayTimeInSecs.get();
}
public void setDisplayTimeInSecs(int displayTime) {
this.displayTimeInSecs.set(displayTime);
}
public IntegerProperty breakBetweenSetsInSecsProperty() {
return breakBetweenSetsInSecs;
}
#XmlElement(name="showIntro")
public Boolean isShowIntro() {
return showIntro.getValue();
}
public void setShowIntro(boolean showIntro) {
this.showIntro.set(showIntro);
}
public BooleanProperty showIntroProperty() {
return showIntro;
}
#XmlElement(name="withMetronom")
public Boolean isWithMetronom() {
return withMetronom.getValue();
}
public void setWithMetronom(boolean withMetronom) {
this.withMetronom.set(withMetronom);
}
public BooleanProperty withMetronomProperty() {
return withMetronom;
}
#XmlElement(name="startSpeed")
public Double getStartSpeed() {
return startSpeed.get();
}
public void setStartSpeed(double startDuration) {
this.startSpeed.set(startDuration);
}
public DoubleProperty startSpeedProperty() {
return startSpeed;
}
#XmlElement(name="endSpeed")
public Double getEndSpeed() {
return endSpeed.get();
}
public void setEndSpeed(double endDuration) {
this.endSpeed.set(endDuration);
}
public DoubleProperty endSpeedProperty() {
return endSpeed;
}
public double getSpeed(int rep) {
if(getStartSpeed().equals(getEndSpeed())) {
return getStartSpeed();
}
double min, max;
if(getStartSpeed() > getEndSpeed()) {
max = getStartSpeed();
min = getEndSpeed();
} else {
min = getStartSpeed();
max = getEndSpeed();
}
double diff = max - min;
double increment = diff / (getRepsPerSet()-1);
return min + rep * increment;
}
#Override
public String toString() {
return getName();
}
}
I used this to marshall
public void save(Session session) {
try {
JAXBContext jc = JAXBContext.newInstance(Session.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(session, new File(System.getProperty("user.home"), ".sifuSays/sessions/" + session.getName() + ".xml"));
} catch (JAXBException e) {
System.err.println("Cannot save session " + session.getName());
e.printStackTrace();
}
}
which generates the following xml file
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Session>
<exerciseList>
<exercise>
<selected>true</selected>
<breakBetweenSetsInSec>5</breakBetweenSetsInSec>
<displayTimeInSecs>-1</displayTimeInSecs>
<endSpeed>3.0</endSpeed>
<mediaFilePath>Tan Pak Gan.mp4</mediaFilePath>
<name>Solo Tan Pak Gan Drill</name>
<numOfSets>2</numOfSets>
<repsPerSet>3</repsPerSet>
<showIntro>false</showIntro>
<startSpeed>1.0</startSpeed>
<withMetronom>false</withMetronom>
</exercise>
<exercise>
<selected>true</selected>
<breakBetweenSetsInSec>5</breakBetweenSetsInSec>
<displayTimeInSecs>-1</displayTimeInSecs>
<endSpeed>1.0</endSpeed>
<mediaFilePath>Chain Punches.mp4</mediaFilePath>
<name>Solo Ein-Arm-Zyklus</name>
<numOfSets>2</numOfSets>
<repsPerSet>4</repsPerSet>
<showIntro>true</showIntro>
<startSpeed>1.0</startSpeed>
<withMetronom>true</withMetronom>
</exercise>
<exercise>
<selected>true</selected>
<breakBetweenSetsInSec>5</breakBetweenSetsInSec>
<displayTimeInSecs>10</displayTimeInSecs>
<endSpeed>1.0</endSpeed>
<mediaFilePath>birddogs.jpg</mediaFilePath>
<name>Stetching</name>
<numOfSets>1</numOfSets>
<repsPerSet>1</repsPerSet>
<showIntro>true</showIntro>
<startSpeed>1.0</startSpeed>
<withMetronom>false</withMetronom>
</exercise>
</exerciseList>
<breakBetweenExercisesInSec>10</breakBetweenExercisesInSec>
<name>MMA - Solo</name>
</Session>
and this is the unmarshaller code
public ObservableList<Session> loadSessions() {
sessions = FXCollections.observableArrayList();
try {
List<File> xmlSessionFiles = Stream.of(
new File(System.getProperty("user.home"), ".sifuSays/sessions/").listFiles())
.filter(file -> !file.isDirectory())
.filter(file -> file.getName().endsWith("xml"))
.collect(Collectors.toList());
for(File xmlSessionFile: xmlSessionFiles) {
JAXBContext jc = JAXBContext.newInstance(Session.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Session session = (Session) unmarshaller.unmarshal(xmlSessionFile);
sessions.add(session);
}
} catch (JAXBException e) {
System.err.println("Cannot load sessions");
e.printStackTrace();
}
return sessions;
}
While numOfSets is marshalled, repsPerset is not. Neither startSpeed or stopSpeed are unmarshalled and neither withMetronom or showIntro. But name and mediaFilePath are marshalled. What's wrong?
You are mixing up boxed (Double, Integer) and unboxed (double, int) types. I recommend sticking to boxed types for marshalling since otherwise you'll end up with things set to 0 that you weren't expecting.
I unmarshal the Document to object as below.
Before that, when parsing XML, use setUserData to store location information for each element.
class MyJaxbAdapter extends XmlAdapter<Object, SubObject> {}
#Override
public UnattendComponent unmarshal(Object v) throws Exception {
Node node = (Node) v; // ElementNSImpl; It's probably a newly created object. Because It is different from the document object given by ownerDocument as SAXSource.
node.getUserData(...) // return NULL
}
}
Document document = ...;
unmarshaller.setAdapter(new MyJaxbAdapter());
MyXMLObject object = unmarshaller.unmarshal(new DOMSource(document), MyXMLObject.class).getValue();
But I can't get UserData inside XmlAdapter's unmarshal method. Is there any way to persist UserData?
Locator information is stored in the properties of Element as shown below.
#Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
Element el = document.createElementNS(usedNamespaceUri, qName);
// ...
el.setUserData(
ElementUserData.class.getName(),
ElementUserData.builder()
.lineNumber(locator.getLineNumber())
.columnNumber(locator.getColumnNumber())
.build(),
null);
}
I need the Locator information (UserData) stored by the above code in the unmarshal of the XmlAdapter.
However, there is no userdata in the node passed as an argument to unmarshal .
Sample Code:
https://github.com/joseph-jclab/jaxb-question-01
Not entirely sure if this is something you are looking for but providing it as a reference so you might get some idea to proceed further:
Sample XML:
<root>
<name>Batman</name>
<year>2008</year>
</root>
Root.class:
#XmlRootElement(name = "root")
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
private String name;
private String year;
#XmlJavaTypeAdapter(CustomAdapter.class)
private String after;
private void afterUnmarshal(Unmarshaller m, Object parent) {
after = name;
}
}
CustomAdapter.class:
public class CustomAdapter extends XmlAdapter<String, String> {
#Override
public String unmarshal(String v) throws Exception {
System.out.println("Within Unmarshal : " + v);
return null;
}
#Override
public String marshal(String v) throws Exception {
System.out.println("Within Marshal : " + v);
return null;
}
}
SampleMain.class:
public class SampleMain {
public static void main(String[] args) throws XMLStreamException, JAXBException {
final InputStream inputStream = Unmarshalling.class.getClassLoader().getResourceAsStream("sample.xml");
final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
final Unmarshaller unmarshaller = JAXBContext.newInstance(Root.class).createUnmarshaller();
unmarshaller.setAdapter(new CustomAdapter());
final Root root = unmarshaller.unmarshal(xmlStreamReader, Root.class).getValue();
System.out.println(root.toString());
Marshaller marshaller = JAXBContext.newInstance(Root.class).createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(root, System.out);
}
}
Output:
Root(name=Batman, year=2008, after=Batman)
Within Marshal : Batman
<root>
<name>Batman</name>
<year>2008</year>
</root>
This seems simple, but I must be missing something. All I am trying to do is unmarshall a JSON array. I have code that works when the JSON is a simple object, but when I make it an array (ie..surround JSON with []), it fails. Here is the sample json, domain class, unmarshalling code, and exception. Any help will be greatly appreciated.
Sample JSON:
[{"CreateIndex":24988,"ModifyIndex":132476,"LockIndex":0,"Key":"Redirector","Flags":0}
]
Domain:
package eclipselink.example.moxy.json.simple.model;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.google.common.base.Optional;
import com.google.common.io.BaseEncoding;
import com.orbitz.consul.model.kv.ImmutableValue;
import com.orbitz.consul.util.UnsignedLongDeserializer;
#org.immutables.value.Value.Immutable
#JsonDeserialize(as = ImmutableValue.class)
#JsonSerialize(as = ImmutableValue.class)
#JsonIgnoreProperties(ignoreUnknown = true)
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class MyValue {
#XmlAttribute
private long createIndex;
#XmlAttribute
private long modifyIndex;
#XmlAttribute
private long lockIndex;
#XmlAttribute
private String key;
#XmlElement
private long flags;
#XmlElement(nillable = true)
private Optional<String> value;
#XmlElement
private Optional<String> session;
#JsonProperty("CreateIndex")
public long getCreateIndex() {
return createIndex;
}
#JsonProperty("ModifyIndex")
public long getModifyIndex() {
return modifyIndex;
}
#JsonProperty("LockIndex")
public long getLockIndex() {
return lockIndex;
}
#JsonProperty("Key")
public String getKey() {
return key;
}
#JsonProperty("Flags")
#JsonDeserialize(using=UnsignedLongDeserializer.class)
public long getFlags() {
return flags;
}
#JsonProperty("Value")
public Optional<String> getValue() {
return value;
}
#JsonProperty("Session")
public Optional<String> getSession() {
return session;
}
#JsonIgnore
#org.immutables.value.Value.Lazy
public Optional<String> getValueAsString() {
if (getValue() != null && getValue().isPresent()) {
return Optional.of(
new String(BaseEncoding.base64().decode(getValue().get()))
);
} else {
return Optional.absent();
}
}
}
Unmarshall code:
public class Main_JSON_redirector {
private static final String INPUT_XML = "META-INF/input.xml";
private static final String INPUT_JSON_URL = "http://192.168.85.186:8500/v1/kv/Redirector";
private static final File INPUT_JSON_FILE = new File("C:/Users/dnance/EclipseLink-examples/moxy/json-simple/src/main/resources/META-INF/redirector.json");
public static void main(String[] args) throws Exception {
System.out.println();
System.out.println("Running EclipseLink MOXy Simple MAIN_JSON Example");
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);
JAXBContext jc = JAXBContext.newInstance(new Class[] {MyValue.class}, properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON);
unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
StreamSource source = new StreamSource(INPUT_JSON_FILE);
JAXBElement<MyValue[]> jaxbElement = unmarshaller.unmarshal(source, MyValue[].class);
MyValue[] value = jaxbElement.getValue();
System.out.println("value: " + value[0].getValueAsString());
...
Exception:
Running EclipseLink MOXy Simple MAIN_JSON Example
Exception in thread "main" javax.xml.bind.UnmarshalException
- with linked exception:
[Exception [EclipseLink-25007] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor for class [Leclipselink.example.moxy.json.simple.model.MyValue; was not found in the project. For JAXB, if the JAXBContext was bootstrapped using TypeMappingInfo[] you must call a marshal method that accepts TypeMappingInfo as an input parameter.]
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.handleXMLMarshalException(JAXBUnmarshaller.java:1072)
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:341)
at eclipselink.example.moxy.json.simple.Main_JSON_redirector.main(Main_JSON_redirector.java:58)
Caused by: Exception [EclipseLink-25007] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor for class [Leclipselink.example.moxy.json.simple.model.MyValue; was not found in the project. For JAXB, if the JAXBContext was bootstrapped using TypeMappingInfo[] you must call a marshal method that accepts TypeMappingInfo as an input parameter.
at org.eclipse.persistence.exceptions.XMLMarshalException.descriptorNotFoundInProject(XMLMarshalException.java:154)
at org.eclipse.persistence.internal.oxm.Context$ContextState.getSession(Context.java:137)
at org.eclipse.persistence.oxm.XMLContext$XMLContextState.getSession(XMLContext.java:798)
at org.eclipse.persistence.oxm.XMLContext$XMLContextState.getSession(XMLContext.java:1)
at org.eclipse.persistence.internal.oxm.Context.getSession(Context.java:458)
at org.eclipse.persistence.oxm.XMLContext.getSession(XMLContext.java:366)
at org.eclipse.persistence.oxm.XMLContext.getSession(XMLContext.java:1)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:837)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:710)
at org.eclipse.persistence.internal.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:643)
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:339)
You just need to specify type class instead of array class in unmarshal method, E.g.
Collection<MyValue> myValues = (Collection<MyValue>) unmarshaller.unmarshal(source, MyValue.class).getValue();
Since you have unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false); it just works. Without it unmarshal returns JAXBElement<Collection<JAXBElement>>.
My JAXB parser suddenly stopped working today. It was working for several weeks. I get the following message. I haven't changed this code for several weeks. Wondering if this set up is good.
EDIT 2: Please could somebody help me! I can't figure this out.
EDIT 1:
My acceptance tests running the same code below are working fine. I believe this is a
classloading issue. I am using the JAXB and StAX in the JDK. However, when I deploy to jboss 5.1, I get the error below. Using 1.6.0_26 (locally) and 1.6.0_30 (dev server). Still puzzling over a solution.
unexpected element (uri:"", local:"lineEquipmentRecord"). Expected
elements are
<{}switchType>,<{}leSwitchId>,<{}nodeAddress>,<{}leId>,<{}telephoneSuffix>,<{}leFormatCode>,<{}groupIdentifier>,<{}telephoneNpa>,<{}telephoneLine>,<{}telephoneNxx>
Here is my unmarshalling class:
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
public class PartialUnmarshaller<T> {
XMLStreamReader reader;
Class<T> clazz;
Unmarshaller unmarshaller;
public PartialUnmarshaller(InputStream stream, Class<T> clazz) throws XMLStreamException, FactoryConfigurationError, JAXBException {
this.clazz = clazz;
this.unmarshaller = JAXBContext.newInstance(clazz).createUnmarshaller();
unmarshaller.setEventHandler(new ValidationEventHandler() {
#Override
public boolean handleEvent(ValidationEvent event) {
System.out.println(event.getMessage());
return true;
}
});
this.reader = XMLInputFactory.newInstance().createXMLStreamReader(stream);
/* ignore headers */
skipElements(XMLStreamConstants.START_DOCUMENT);
/* ignore root element */
reader.nextTag();
/* if there's no tag, ignore root element's end */
skipElements(XMLStreamConstants.END_ELEMENT);
}
public T next() throws XMLStreamException, JAXBException {
if (!hasNext())
throw new NoSuchElementException();
T value = unmarshaller.unmarshal(reader, clazz).getValue();
skipElements(XMLStreamConstants.CHARACTERS, XMLStreamConstants.END_ELEMENT);
return value;
}
public boolean hasNext() throws XMLStreamException {
return reader.hasNext();
}
public void close() throws XMLStreamException {
reader.close();
}
private void skipElements(Integer... elements) throws XMLStreamException {
int eventType = reader.getEventType();
List<Integer> types = new ArrayList<Integer>(Arrays.asList(elements));
while (types.contains(eventType))
eventType = reader.next();
}
}
This class is used as follows:
List<MyClass> lenList = new ArrayList<MyClass>();
PartialUnmarshaller<MyClass> pu = new PartialUnmarshaller<MyClass>(
is, MyClass.class);
while (pu.hasNext()) {
lenList.add(pu.next());
}
The XML being unmarshalled:
<?xml version="1.0" encoding="UTF-8"?>
<lineEquipment>
<lineEquipmentRecord>
<telephoneNpa>333</telephoneNpa>
<telephoneNxx>333</telephoneNxx>
<telephoneLine>4444</telephoneLine>
<telephoneSuffix>1</telephoneSuffix>
<nodeAddress>xxxx</nodeAddress>
<groupIdentifier>LEN</groupIdentifier>
</lineEquipmentRecord>
<lineEquipmentRecord>
<telephoneNpa>111</telephoneNpa>
<telephoneNxx>111</telephoneNxx>
<telephoneLine>2222</telephoneLine>
<telephoneSuffix>0</telephoneSuffix>
<nodeAddress>xxxx</nodeAddress>
<groupIdentifier>LEN</groupIdentifier>
</lineEquipmentRecord>
</lineEquipment>
Finally, here is MyClass:
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* This class is used as an envelope to hold Martens
* line equipment information.
* #author spgezf
*
*/
#XmlRootElement(name="lineEquipmentRecord")
public class MyClass {
private String telephoneNpa;
private String telephoneNxx;
private String telephoneLine;
private String telephoneSuffix;
private String nodeAddress;
private String groupIdentifier;
public MyClass(){
}
// Getters and Setters.
#XmlElement(name="telephoneNpa")
public String getTelephoneNpa() {
return telephoneNpa;
}
public void setTelephoneNpa(String telephoneNpa) {
this.telephoneNpa = telephoneNpa;
}
#XmlElement(name="telephoneNxx")
public String getTelephoneNxx() {
return telephoneNxx;
}
public void setTelephoneNxx(String telephoneNxx) {
this.telephoneNxx = telephoneNxx;
}
#XmlElement(name="telephoneLine")
public String getTelephoneLine() {
return telephoneLine;
}
public void setTelephoneLine(String telephoneLine) {
this.telephoneLine = telephoneLine;
}
#XmlElement(name="telephoneSuffix")
public String getTelephoneSuffix() {
return telephoneSuffix;
}
public void setTelephoneSuffix(String telephoneSuffix) {
this.telephoneSuffix = telephoneSuffix;
}
#XmlElement(name="nodeAddress")
public String getNodeAddress() {
return nodeAddress;
}
public void setNodeAddress(String nodeAddress) {
this.nodeAddress = nodeAddress;
}
#XmlElement(name="groupIdentifier")
public String getGroupIdentifier() {
return groupIdentifier;
}
public void setGroupIdentifier(String groupIdentifier) {
this.groupIdentifier = groupIdentifier;
}
}
Thanks, this is classloading issue I couldn't overcome so I abandoned JAXB.
Your PartialUnmarshaller code worked for me. Below is an alternate version that changes the skipElements method that may work better.
import java.io.InputStream;
import java.util.NoSuchElementException;
import javax.xml.bind.*;
import javax.xml.stream.*;
public class PartialUnmarshaller<T> {
XMLStreamReader reader;
Class<T> clazz;
Unmarshaller unmarshaller;
public PartialUnmarshaller(InputStream stream, Class<T> clazz) throws XMLStreamException, FactoryConfigurationError, JAXBException {
this.clazz = clazz;
this.unmarshaller = JAXBContext.newInstance(clazz).createUnmarshaller();
unmarshaller.setEventHandler(new ValidationEventHandler() {
#Override
public boolean handleEvent(ValidationEvent event) {
System.out.println(event.getMessage());
return true;
}
});
this.reader = XMLInputFactory.newInstance().createXMLStreamReader(stream);
/* ignore headers */
skipElements();
/* ignore root element */
reader.nextTag();
/* if there's no tag, ignore root element's end */
skipElements();
}
public T next() throws XMLStreamException, JAXBException {
if (!hasNext())
throw new NoSuchElementException();
T value = unmarshaller.unmarshal(reader, clazz).getValue();
skipElements();
return value;
}
public boolean hasNext() throws XMLStreamException {
return reader.hasNext();
}
public void close() throws XMLStreamException {
reader.close();
}
private void skipElements() throws XMLStreamException {
while(reader.hasNext() && !reader.isStartElement()) {
reader.next();
}
}
}
Imagine I have enum defined like this:
public enum ArchiveStatus implements Serializable {
CANDIDATE (0, "CANDIDATE", "Candidate for archival"),
IN_LIBRARY (1, "IN-LIBRARY", ".."),
FROM_LIBRARY (2, "FROM-LIBRARY", "..");
private int id;
private String shortName;
private String longName;
public ArchiveStatus( int id, String shortName, String longName ) {
..
}
public int getId() { .. }
public String getShortName() { .. }
public String getLongName() { .. }
}
By default MOXy is going to serialize it to JSON like this:
{
..
"archiveStatus": "CANDIDATE",
..
}
Is there a way to configure MOXy (in the mapping file) to serialize the enum like a regular class:
{
..
"archiveStatus": { "id" : 0, "shortName": "CANDIDATE", "longName": "Candidate for archival" },
..
}
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
ArchiveStatusAdapter
You can solve this use case by leveraging an XmlAdapter. XmlAdapter is a JAXB mechanism that allows you to marshal one type of object as another.
package forum10144489;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class ArchiveStatusAdapter extends XmlAdapter<ArchiveStatusAdapter.AdaptedArchiveStatus, ArchiveStatus> {
public static class AdaptedArchiveStatus {
public int id;
public String shortName;
public String longName;
}
#Override
public ArchiveStatus unmarshal(AdaptedArchiveStatus adaptedArchiveStatus) throws Exception {
if(null == adaptedArchiveStatus) {
return null;
}
return ArchiveStatus.valueOf(adaptedArchiveStatus.shortName);
}
#Override
public AdaptedArchiveStatus marshal(ArchiveStatus archiveStatus) throws Exception {
if(null == archiveStatus) {
return null;
}
AdaptedArchiveStatus adaptedArchiveStatus = new AdaptedArchiveStatus();
adaptedArchiveStatus.id = archiveStatus.getId();
adaptedArchiveStatus.longName = archiveStatus.getLongName();
adaptedArchiveStatus.shortName = archiveStatus.getShortName();
return adaptedArchiveStatus;
}
}
Root
The XmlAdapter can be specified at the field, property, type, or package level using the #XmlJavaTypeAdapter annotation.
package forum10144489;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
public class Root {
private ArchiveStatus archiveStatus;
#XmlJavaTypeAdapter(ArchiveStatusAdapter.class)
public ArchiveStatus getArchiveStatus() {
return archiveStatus;
}
public void setArchiveStatus(ArchiveStatus archiveStatus) {
this.archiveStatus = archiveStatus;
}
}
jaxb.properties
To specify MOXy as your JAXB provider you need to add a file called jaxb.properties in the same package as your domain classes with the following entry.
javax.xml.bind.context.factory = org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
package forum10144489;
import java.io.StringReader;
import java.util.*;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>(2);
properties.put("eclipselink.media-type", "application/json");
properties.put("eclipselink.json.include-root", false);
JAXBContext jc = JAXBContext.newInstance(new Class[] {Root.class}, properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StringReader jsonStringReader = new StringReader("{\"archiveStatus\" : {\"id\" : 0, \"shortName\" : \"CANDIDATE\", \"longName\" : \"Candidate for archival\"}}");
StreamSource jsonSource = new StreamSource(jsonStringReader);
Root root = unmarshaller.unmarshal(jsonSource, Root.class).getValue();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
Output
Below is the output from running the demo code:
{
"archiveStatus" : {
"id" : 0,
"shortName" : "CANDIDATE",
"longName" : "Candidate for archival"
}
}
For More Information
http://blog.bdoughan.com/2011/08/json-binding-with-eclipselink-moxy.html
http://blog.bdoughan.com/search/label/XmlAdapter
http://blog.bdoughan.com/search/label/jaxb.properties