'Jaxb marshalling parts of xml with keeping original namespacess prefix

I am using below plugin to generate jaxb classes. I then read some XML from filesystem and unmarshall it to generated jaxb classes. Those classes has collection of entries that I need to unmarshall separately, do some business logic and for each part unmarshalled and store them as xml parts. So in fact I am doing XML -> Object (to do some business logic) -> smaller XMLs which I am storing somewhere. Problem is that the XML in filesystem has correct namespaces prefixes (like tca, tcb, tcc) and while marshalling those smaller parts back to xml, jaxb creates its own namespaces prefixes like ns1, ns2, ns3. Is it possible to have tca, tcb, tcc as in original file ? But maybe not to define my own prefixes map because I never know what prefixes will come to my filesystem. Some external party may change them in future and I only want to keep original ones. Belo is my code.

Code generation plugin:

<plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>jaxb2-maven-plugin</artifactId>
                <version>${jaxb2-maven-plugin.version}</version>
                <executions>
                    <execution>
                        <id>xjc</id>
                        <goals>
                            <goal>xjc</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <sources>
                        <source>src/main/resources/my.xsd</source>
                    </sources>
                    <outputDirectory>${basedir}/target/generated-sources/java</outputDirectory>
                    <clearOutputDir>false</clearOutputDir>
                </configuration>
            </plugin>

The code

        JAXBContext jaxbContext = JAXBContext.newInstance(MyRoot.class);

        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        while (streamReader.hasNext()) {
            if (streamReader.isStartElement()) {
                if (streamReader.getName() != null && streamReader.getName().getLocalPart() != null) {
                    String localPart = streamReader.getName().getLocalPart();
                    if (localPart.equalsIgnoreCase(XmlElements.CAR)) {
                        JAXBElement<Car> carJAXBElement = unmarshaller.unmarshal(streamReader, Car.class);
                        //doing some business logic 
                        JAXBContext context = JAXBContext.newInstance(Car.class);
                        Marshaller m = context.createMarshaller();
                        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
                        StringWriter sw = new StringWriter();
                        m.marshal(carJAXBElement, sw);
                        String result = sw.toString();  //the result has namespaces prefixes changed
                        //and then saving one car xml part somewhere
                       
                    }
                }
            }
            streamReader.next();

The xml files

Original file:

<?xml version="1.0" encoding="UTF-8"?>
<tca:myroot xmlns:tca="http://myspec/tca/1.0" >
    <tca:car>
        <tca:owner>
            <tca:name>
            </tca:name>
        </tca:owner>
    </tca:car>
    <tca:car>
        <tca:owner>
            <tca:name>
            </tca:name>
        </tca:owner>
    </tca:car>
</tca:myroot>

Marshalled car xml part:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns4:car xmlns:ns4="http://myspec/tca/1.0" >
    <ns4:owner>
        <ns4:name>
        </ns4:name>
    </ns4:owner>
</ns4:car>

Is it possible to have original namespaces prefixes in those small car parts after marshalling them?



Solution 1:[1]

So despite there were no answers, I've figured it out by myself.. So I am adding info for future searchers - please mark my answer as valid if u will find it useful because I don't want to do it by myself.

I used NamespacePrefixMapper where I had mapping prefix -> namespace uri for each namespace read in xml file from its first element. It worked fine, but Sonar was complaining that I am using sun internal classes:

 JAXBContext context = JAXBContext.newInstance(clazz);
        Marshaller m = context.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        m.setProperty("com.sun.xml.bind.namespacePrefixMapper", new MyNamespacePrefixMapper(namespaces));

So I then used package-info.java approach. I noticed, that jaxb2-maven-plugin xjc goal creates default package-info.java. Inside this file it is possible to add your own namespace prefix to namespace uri mapping. Then I used maven-resources-plugin to copy my own package-info.java to package of generated classes. Finally when marshaller is converting objects back to xml files, it uses my package-info.java and original namespace prefixes are preserved instead of ns1, ns2, etc.

<plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-resources</id>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <overwrite>true</overwrite>
                            <outputDirectory>${basedir}/target/generated-sources/java/package_where_default_package_info_is_generated</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>${basedir}/src/main/resources/bindings</directory>
                                    <include>package-info.java</include>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>        

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Frankio1