Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to unmarshall a XML without namespace using the Jakarta XML Unmarshaller? #2085

Open
Aravinda93 opened this issue Mar 4, 2024 · 0 comments

Comments

@Aravinda93
Copy link

Aravinda93 commented Mar 4, 2024

I am trying to unmarshal an XML into a Java object using the jakarta.xml.bind.Unmarshaller but my XML does not contain some of the default namespaces as they are part of the XSD already. How to either explicitly mention to Unmarshaller to ignore these default namespaces or add them to the XMLStreamReader at the runtime so Unmarshaller can use them?

Following is the XML which fails to unmarshal to Java object:

<foo>
    <bar>Hello</bar>
    <test:one>Hello ONE</test:one>
</foo>

If I change to this then it would work as expected:

<foo>
    <bar>Hello</bar>
    <test:one xmlns:test="https://test.com">Hello ONE</test:one>
</foo>

I looked at a few examples on StackOverflow but the provided approach does not work. I do not wish to use an additional library such as Sax rather I want to handler at the XMLStreamReader level or by using the Unmarshaller.

How to achieve this?

Following is the method for doing the unmarshalling of XML:

Main.class:

import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Unmarshaller;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.InputStream;

public class Main {
    public static void main(String[] args) throws XMLStreamException, JAXBException {
        final XMLInputFactory inputFactory = XMLInputFactory.newInstance();
        inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
        inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
        final InputStream inputStream = Main.class.getResourceAsStream("/SampleXML.xml");
        final XMLStreamReader xmlStreamReader = inputFactory.createXMLStreamReader(inputStream);
        final JAXBContext jaxbContext = JAXBContext.newInstance("io.convert.test", Thread.currentThread().getContextClassLoader());
        final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        xmlStreamReader.next();

        while (xmlStreamReader.hasNext()) {
            Object event = unmarshaller.unmarshal(xmlStreamReader, Foo.class).getValue();
            System.out.println(event.toString());
        }
    }
}

Foo.class:


import jakarta.xml.bind.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.util.List;

@Data
@NoArgsConstructor
@AllArgsConstructor
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "foo")
@XmlType(
        name = "Foo",
        propOrder = {
                "bar",
                "anyElements"
        },
        factoryClass = ObjectFactory.class,
        factoryMethod = "createFoo")
@ToString(callSuper = true)
public class Foo {
    private String bar;
    
    @XmlAnyElement(lax = true)
    private List<Object> anyElements;
}

ObjectFactory.class:

import jakarta.xml.bind.annotation.XmlRegistry;

@XmlRegistry
public final class ObjectFactory {
  private ObjectFactory() {}
  public static Foo createFoo() {
    return new Foo();
  }
}

An error occurred when XML used without namespace:

Exception in thread "main" jakarta.xml.bind.UnmarshalException
 - with linked exception:
[Exception [EclipseLink-25004] (Eclipse Persistence Services - 4.0.2.v202306161219): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred unmarshalling the document
Internal Exception: javax.xml.stream.XMLStreamException: ParseError at [row,col]:[3,15]
Message: http://www.w3.org/TR/1999/REC-xml-names-19990114#ElementPrefixUnbound?test&test:one]
	at org.eclipse.persistence.jaxb.JAXBUnmarshaller.handleXMLMarshalException(JAXBUnmarshaller.java:1132)
	at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:471)
	at io.convert.test.Main.main(Main.java:24)
Caused by: Exception [EclipseLink-25004] (Eclipse Persistence Services - 4.0.2.v202306161219): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred unmarshalling the document

Based on few response I tried adding the additional class to return the namespaces but that did not work either NamespaceIgnoringXMLStreamReader.clas

import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.util.StreamReaderDelegate;

public class NamespaceIgnoringXMLStreamReader extends StreamReaderDelegate {
    public NamespaceIgnoringXMLStreamReader(XMLStreamReader reader) {
        super(reader);
    }
    @Override
    public String getAttributeNamespace(int arg0) {
        return "";
    }
    @Override
    public String getNamespaceURI() {
        return "";
    }
}

Then using those streams in Main.class:

final XMLStreamReader xmlStreamReader = inputFactory.createXMLStreamReader(inputStream);
NamespaceIgnoringXMLStreamReader namespaceIgnoringReader = new NamespaceIgnoringXMLStreamReader(xmlStreamReader);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant