I'm trying to parse a GPX file using JAXBU here is my code:
GpxType unmarshal(String path) {
GpxType list = new GpxType();
try {
javax.xml.bind.JAXBContext jaxbCtx = javax.xml.bind.JAXBContext
.newInstance(list.getClass().getPackage().getName());
javax.xml.bind.Unmarshaller unmarshaller = jaxbCtx.createUnmarshaller();
list = (GpxType) unmarshaller.unmarshal(new java.io.File(path)); //NOI18N
return list;
} catch (javax.xml.bind.JAXBException ex) {
// XXXTODO Handle exception
java.util.logging.Logger.getLogger("global")
.log(java.util.logging.Level.SEVERE, null, ex); //NOI18N
}
return null;
}
however i get the following error:
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException:
javax.xml.bind.JAXBElement cannot be cast to GPXfiles.GpxType
so im guessing its because using JAXBU its looking for a XML file instead of a GPX file. Any help would be appreciated :)
You can call JAXBIntrospector.getValue(Object) on the result of the unmarshal operation to guard against the result being wrapped in a JAXBElement.
Related
XML Input:
<Root_to_unwrap><User name="a"></User></Root_to_unwrap>
Java Record:
package x.y.z;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
public record User(#JacksonXmlProperty(isAttribute = true) String name) {
}
Tried the following with Jackson version 2.13.3, both doesn't work:
Try #1
#Test
void testCase1() {
try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("input.xml")) {
XmlMapper xmlMapper = new XmlMapper();
ObjectReader reader = xmlMapper.reader().withFeatures(DeserializationFeature.UNWRAP_ROOT_VALUE);
User user = reader.readValue(is, User.class);
} catch (IOException ioe) {
fail(ioe); // failed with "Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not set final java.lang.String field x.y.z.User.name to java.lang.String"
}
}
Try #2
#Test
void testCase2() {
try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("input.xml")) {
XmlMapper xmlMapper = new XmlMapper();
ObjectReader reader = xmlMapper.reader().withRootName("Root_to_unwrap").withFeatures(DeserializationFeature.UNWRAP_ROOT_VALUE);
User user = reader.readValue(is, User.class);
} catch (IOException ioe) {
fail(ioe); // failed with "Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Root name ('User') does not match expected ('Root_to_unwrap') for type `x.y.z.User`"
}
}
Any idea how deserialize XML into Record? Thank you!
The Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not set final java.lang.String... exception message is related to the fact that Jackson library because of the absence of a JsonCreator annotated method in the User record firstly creates the User record and then tries to modify the final field called name, then the exception. This scenario can be avoided adding a JsonCreator annotated constructor to your User record :
public record User(#JacksonXmlProperty(isAttribute = true) String name) {
#JsonCreator
public User(String name) {
this.name = name;
}
}
I tried your code with the Jackson version 2.12 with no luck (maybe the constructor in the User record solves your issue with jackson 2.13, but I haven't verified it), using one incremental reading as suggested in the official documentation solves your problem:
File xml = new File("msg.xml");
XMLInputFactory f = XMLInputFactory.newFactory();
XMLStreamReader sr = f.createXMLStreamReader(new FileInputStream(xml));
XmlMapper xmlMapper = new XmlMapper();
sr.nextTag(); //points to Root_to_unwrap tag
sr.nextTag(); //points to User tag
User user = xmlMapper.readValue(sr, User.class);
sr.close();
I convert element xml to object with this code:
public static Object xmlToObject(Element element, Class c, org.apache.logging.log4j.Logger log) {
try {
if (log != null) {
log.debug(element);
log.debug("este es el resultado ");
}
JDOMSource source = new JDOMSource(element);
JAXBContext context = JAXBContext.newInstance(c);
Unmarshaller un = context.createUnmarshaller();
return un.unmarshal(source);
} catch (JAXBException ex) {
java.util.logging.Logger.getLogger(SiodexClient.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
in weblogic 10 works and console java normal execution too, but in weblogic 12 dont works why?
this is error:
[Exception [EclipseLink-25008] (Eclipse Persistence Services - 2.6.5.v20170607-b3d05bd): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor with default root element cod_tipo_operacion was not found in the project]
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.handleXMLMarshalException(JAXBUnmarshaller.java:1110)
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:335)
at mefp.itg.clws.bcb.siodex.SiodexClient.xmlToObject(SiodexClient.java:216)
help please
I'm try to validate an XML using StAX and javax Validator however I'm getting the following cast error:
org.xml.sax.SAXException: java.lang.ClassCastException: org.codehaus.stax2.ri.evt.NamespaceEventImpl cannot be cast to java.lang.String
javax.xml.transform.TransformerException: java.lang.ClassCastException: org.codehaus.stax2.ri.evt.NamespaceEventImpl cannot be cast to java.lang.String
The basic idea is that I need to parse an XML using StAX and I'm attempting to reuse the event reader I'll be using for parsing and creating a StAXSource to perform the validation.
I was able to debug the error and trace the cast exception to the class com.sun.org.apache.xalan.internal.xsltc.trax.StAXEvent2SAX, line 341, where there is a loop through an iterator and a cast to a String when in fact the iterator has the type NamespaceEventImpl (snippet code of the portion of code below).
// end namespace bindings
for( Iterator i = event.getNamespaces(); i.hasNext();) {
String prefix = (String)i.next();
if( prefix == null ) { // true for default namespace
prefix = "";
}
_sax.endPrefixMapping(prefix);
}
The following is the content of the iterator "i" while performing the logic I'm referring to:
iterator content
Below is a snippet of code describing how I'm doing it.
public void validateRequest(RequestMessage message) {
try {
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLEventReader eventReader = factory.createXMLEventReader(new ByteArrayInputStream(message.getMessage().getBytes()));
this.validateSchema(eventReader);
if(this.isSchemaValid()) {
// parse through XML
}
} catch(Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
private void validateSchema(XMLEventReader eventReader) {
try {
StAXErrorHandler errorHandler = new StAXErrorHandler();
this.validator.setErrorHandler(errorHandler);
this.validator.validate(new StAXSource(eventReader));
} catch (SAXException | IOException | XMLStreamException e) {
LOGGER.error(e.getMessage(), e);
}
}
I was wondering if someone faced this issue before and if it is a limitation of using StAXSource with the Validator itself.
I need to log XML message.
I use this code:
//From object to xml
public String createMarshalerDealInfoType(DealInfoType dealInfoType) {
StringWriter contactStr = null;
try {
JAXBContext jaxbContext = JAXBContext.newInstance(DealInfoType.class);
Marshaller jaxbUnmarshaller = jaxbContext.createMarshaller();
contactStr = new StringWriter();
jaxbUnmarshaller.marshal(dealInfoType, contactStr);
} catch (JAXBException e) {
log.error(e.getMessage());
}
return contactStr.toString();
}
In test class:
ResponseType ResponseType = woNspDealWS.createRequestWS(DealRequestType);
String DealResponce = updateDealEsb.createMarshalerDealInfoType(ResponseType.getDealInfo());
log.debug("Response: \n " + DealResponce);
Problem: in log output I see only first line of responce, not whole message
18:01:42,975 DEBUG updateDeal_Test:73 - Response: <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
How do I make to print all response in XML?
SOLVED:
resolved problem with use annotation #XmlRootElement for test class.
The object which you have passed in test class might be empty
ResponseType.getDealInfo()
For solving this problem need use annotation #XmlRootElement in test class
I'm currently trying to unmarshal some XML into a java object using JAXB and I'm getting a strange Null Pointer Exception. This is only an issue while unmarshalling. I can marshal with these classes just fine. Here are the relevant pieces of code (irrelevant portions are denoted by "..."):
The JAXB Root element:
...
#XmlRootElement(name="assets")
public class Assets {
String product;
Images images = new Images();
...
Public Assets() {}
...
public String getProduct() { return this.product; }
#XmlAttribute(name="product")
public void setProduct(String newProduct) { this.product = newProduct; }
public Images getImages() { return this.images; }
#XmlElement(name="images")
public void setImages(Images newImages) { this.images = newImages; }
...
}
The Images sub-element of the root element:
...
#XmlRootElement(name="images")
#XmlSeeAlso(Image.class)
#XmlType(propOrder = {"mainAsset", "image"})
public class Images {
List<Image> images;
Image mainAsset;
private static char counter = 'a';
private static final String prefix = "product-image-";
// Here's the part that causes the NPE
#XmlAnyElement(lax=true)
public List<JAXBElement<Image>> getImage() {
final List<JAXBElement<Image>> imageList = new ArrayList<JAXBElement<Image>>();
for (final Image g : this.images) {
imageList.add(new JAXBElement(new QName(prefix + counter++), Image.class, g));
}
counter = 'a';
return imageList;
}
#XmlElement(name="renditions")
public void setImage(List<Image> newImages) { this.images = newImages; }
public Image getMainAsset() { return this.mainAsset; }
#XmlElement(name="main-asset-name")
public void setMainAsset(Image newMainAsset) { this.mainAsset = newMainAsset; }
}
The logic for unmarshalling the XML:
...
public void modifyXML() {
try {
JAXBContext context = JAXBContext.newInstance(Assets.class, Images.class, Image.class);
Unmarshaller um = context.createUnmarshaller();
File f = new File("/path/to/my.xml");
Assets assets = (Assets) um.unmarshal(f);
...
} catch (JAXBException e) {
e.printStackTrace();
}
}
...
Finally, the XML I'm trying to unmarshal (it might help to know that this xml file was actually generated using the JAXB marshaller, which runs without any problems):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assets product="TEST PRODUCT">
<images>
<main-asset-name>
<path>stuff.jpg</path>
<title>theTitle</path>
<alt>theAlt</path>
<description>theDescription</description>
</main-asset-name>
<product-image-a>
<path>48x48.jpg</path>
<title>theTitle</path>
<alt>theAlt</path>
<description>theDescription</description>
</product-image-a>
<product-image-b>
<path>140x140.jpg</path>
<title>theTitle</path>
<alt>theAlt</path>
<description>theDescription</description>
</product-image-b>
<product-image-c>
<path>1280x1280.jpg</path>
<title>theTitle</path>
<alt>theAlt</path>
<description>theDescription</description>
</product-image-c>
<product-image-d>
<path>319x319.jpg</path>
<title>theTitle</path>
<alt>theAlt</path>
<description>theDescription</description>
</product-image-d>
</images>
</assets>
Okay, so that's all the relevant code (I think). When I run my program, I get the following error right after invoking the unmarshaller:
java.lang.NullPointerException
at com.my.companys.name.Images.getImage(Images.java:25)
And the line number referenced is the line where the for loop starts in my Images.java class file.
Does anyone have any ideas why this.images might be null here? Any help is greatly appreciated. Thanks ahead of time.
Here's the solution I've been using for now. It's a bit of a hack, but hell... It does the job.
First, I get the raw xml as a string instead of reading it as a file:
public void modifyXML() {
try {
JAXBContext context = JAXBContext.newInstance(Assets.class, Image.class);
Unmarshaller um = context.createUnmarshaller();
// This xml should be formatted in a way that JAXB can work with
String rawXML = getRawXML("/path/to/my.xml");
// Hand the modified xml to the unmarshaller
Assets umAssets = (Assets) um.unmarshal(new StreamSource(new StringReader(rawXML)));
// Do stuff with umAssets
...
} catch (Exception e) {
e.printStackTrace();
}
}
private String getRawXML(String path) throws IOException {
String xml = readFile(path, StandardCharsets.UTF_8);
// This should make it so JAXB can handle the xml properly
xml = xml.replaceAll("<main-asset-name>", "<image>");
xml = xml.replaceAll("</main-asset-name>", "</image>");
xml = xml.replaceAll("<product-image.*>", "<image>");
return xml.replaceAll("</product-image.*>", "</image>");
}
private String readFile(String path, Charset encoding) throws IOException {
// A simple file reader
byte[] encoded = Files.readAllBytes(Paths.get(path));
return new String(encoded, encoding);
}
This seems to do the trick, so I'm going to use this for now. Of course, I'm still open to better solutions if anyone has one.