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

Fix (un)marshal bug #1135 #1294

Merged
merged 2 commits into from
Nov 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions jaxb-ri/runtime/impl/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
<argLine>
--add-opens org.glassfish.jaxb.runtime/com.sun.xml.bind.v2=java.xml.bind
--add-opens org.glassfish.jaxb.runtime/com.sun.xml.bind.v2.schemagen=java.xml.bind
--add-opens org.glassfish.jaxb.runtime/com.sun.xml.bind.v2.schemagen.xmlidref=java.xml.bind
</argLine>
</configuration>
</plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;

import com.sun.xml.bind.v2.model.core.ClassInfo;
import com.sun.xml.bind.v2.model.core.ID;
import com.sun.xml.bind.v2.model.core.PropertyKind;
import com.sun.xml.bind.v2.model.runtime.RuntimeAttributePropertyInfo;
Expand Down Expand Up @@ -126,6 +127,9 @@ static boolean isLeaf(RuntimePropertyInfo info) {
// IDREF is always handled as leaf -- Transducer maps IDREF String back to an object
return true;

//if hasSubClasses it's not a leaf and we can't optimize, see #1135
if (rti instanceof ClassInfo && ((ClassInfo) rti).hasSubClasses()) return false;

if(((RuntimeNonElement)rti).getTransducer()==null)
// Transducer!=null means definitely binds to PCDATA.
// even if transducer==null, a referene might be IDREF,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
/*
* Copyright (c) 1997, 2019 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

package com.sun.xml.bind.v2.schemagen;

import org.junit.Assert;
import org.junit.Test;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlValue;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import com.sun.xml.bind.v2.schemagen.xmlidref.JaxbConcreteContainer;
import com.sun.xml.bind.v2.schemagen.xmlidref.JaxbConcreteDeployment;
import com.sun.xml.bind.v2.schemagen.xmlidref.JaxbContainer;
import com.sun.xml.bind.v2.schemagen.xmlidref.JaxbDistribution;
import com.sun.xml.bind.v2.schemagen.xmlidref.JaxbEnvironmentModel;

import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;

import junit.framework.TestCase;
import junit.textui.TestRunner;

public class MarshallingAbstractTest extends TestCase {
public static void main(String[] args) {
TestRunner.run(MarshallingAbstractTest.class);
}

@XmlSeeAlso({B.class, C.class})
abstract static class A {
//marshal/unmarshal of list elements containing elements of type = A will work without @XmlValue annotation...
@XmlValue
protected String value;
}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ClassType1")
public static class B extends A {
public B() {}
public B(String value) {
this.value = value;
}
}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ClassType2")
public static class C extends A {
public C() {}
public C(String value) {
this.value = value;
}
}

@XmlRootElement(name="root")
@XmlAccessorType(XmlAccessType.FIELD)
static class Mapping {
@XmlElementWrapper(name = "list")
@XmlElement(name="element")
Collection<A> list = new ArrayList<A>();
A element1;
A element2;
}

@Test
public void testMarshalSingleElement() throws Exception {
JAXBContext jc = JAXBContext.newInstance(Mapping.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
StringWriter resultWriter = new StringWriter();
Mapping mapping = new Mapping();
mapping.element1 = new B("B1");
mapping.element2 = new C("C1");
marshaller.marshal(mapping, resultWriter);

String expectedXml1 = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<root>\n"
+ " <list/>\n"
+ " <element1 xsi:type=\"ClassType1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">B1</element1>\n"
+ " <element2 xsi:type=\"ClassType2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">C1</element2>\n"
+ "</root>\n";
Assert.assertEquals(resultWriter.toString(), expectedXml1);
}

@Test
public void testMarshalCollection() throws Exception {
JAXBContext jc = JAXBContext.newInstance(Mapping.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
StringWriter resultWriter = new StringWriter();
Mapping mapping = new Mapping();
mapping.element1 = new B("B1");
mapping.element2 = new C("C1");
mapping.list.add(new B("B"));
mapping.list.add(new C("C"));
String expectedXml2 = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<root>\n"
+ " <list>\n"
+ " <element xsi:type=\"ClassType1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">B</element>\n"
+ " <element xsi:type=\"ClassType2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">C</element>\n"
+ " </list>\n"
+ " <element1 xsi:type=\"ClassType1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">B1</element1>\n"
+ " <element2 xsi:type=\"ClassType2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">C1</element2>\n"
+ "</root>\n";
marshaller.marshal(mapping, resultWriter);
Assert.assertEquals(resultWriter.toString(), expectedXml2);
}

@Test
public void testUnmarshalSingleElement() throws Exception {
JAXBContext jc = JAXBContext.newInstance(Mapping.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
//works without list..
String sourceXml1 = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<root>\n"
+ " <element1 xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"ClassType1\">B1</element1>\n"
+ " <element2 xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"ClassType2\">C1</element2>\n"
+ "</root>\n";
JAXBElement<Mapping> element = unmarshaller.unmarshal(new StreamSource(new StringReader(sourceXml1)), Mapping.class);
Assert.assertNotNull(element.getValue());
Assert.assertEquals(B.class, element.getValue().element1.getClass());
Assert.assertEquals(C.class, element.getValue().element2.getClass());
}

@Test
public void testUnmarshalCollection() throws Exception {
JAXBContext jc = JAXBContext.newInstance(Mapping.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
//don't work -> try to instantiate the abstract class
String sourceXml2 = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<root>\n"
+ " <list>\n"
+ " <element xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"ClassType1\">B</element>\n"
+ " <element xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"ClassType2\">C</element>\n"
+ " </list>\n"
+ " <element1 xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"ClassType1\">B1</element1>\n"
+ " <element2 xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"ClassType2\">C1</element2>\n"
+ "</root>\n";

try {
JAXBElement<Mapping> element = unmarshaller.unmarshal(new StreamSource(new StringReader(sourceXml2)), Mapping.class);
Assert.assertEquals(2, element.getValue().list.size());
}
catch (Throwable e) {
Assert.fail();
}
}

@Test
public void testXmlIDRefMarshal() throws Exception {

JAXBContext cont = JAXBContext.newInstance(JaxbEnvironmentModel.class);
JaxbEnvironmentModel envModel = new JaxbEnvironmentModel();
JaxbDistribution dist = new JaxbDistribution();
JaxbConcreteDeployment dep = new JaxbConcreteDeployment();
dep.setContextRoot("Context-Root");
dist.addDeployment(dep);
envModel.setDistribution(dist);
JaxbContainer container = new JaxbConcreteContainer();
container.addDeployment(dep);
envModel.setContainer(container);

String sourceXsd = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" +
"<xs:schema version=\"1.0\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n" +
"\n" +
" <xs:element name=\"environmentModel\" type=\"environmentModelType\"/>\n" +
"\n" +
" <xs:complexType name=\"environmentModelType\">\n" +
" <xs:sequence>\n" +
" <xs:element name=\"container\" type=\"containerType\" minOccurs=\"0\"/>\n" +
" <xs:element name=\"distribution\" type=\"distributionType\" minOccurs=\"0\"/>\n" +
" </xs:sequence>\n" +
" </xs:complexType>\n" +
"\n" +
" <xs:complexType name=\"containerType\" abstract=\"true\">\n" +
" <xs:sequence>\n" +
" <xs:element name=\"deployments\">\n" +
" <xs:complexType>\n" +
" <xs:sequence>\n" +
" <xs:element name=\"deployment\" type=\"xs:IDREF\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n" +
" </xs:sequence>\n" +
" </xs:complexType>\n" +
" </xs:element>\n" +
" </xs:sequence>\n" +
" </xs:complexType>\n" +
"\n" +
" <xs:complexType name=\"deploymentType\" abstract=\"true\">\n" +
" <xs:sequence>\n" +
" <xs:element name=\"contextRoot\" type=\"xs:ID\"/>\n" +
" </xs:sequence>\n" +
" </xs:complexType>\n" +
"\n" +
" <xs:complexType name=\"concreteDeploymentType\">\n" +
" <xs:complexContent>\n" +
" <xs:extension base=\"deploymentType\">\n" +
" <xs:sequence/>\n" +
" </xs:extension>\n" +
" </xs:complexContent>\n" +
" </xs:complexType>\n" +
"\n" +
" <xs:complexType name=\"concreteContainerType\">\n" +
" <xs:complexContent>\n" +
" <xs:extension base=\"containerType\">\n" +
" <xs:sequence/>\n" +
" </xs:extension>\n" +
" </xs:complexContent>\n" +
" </xs:complexType>\n" +
"\n" +
" <xs:complexType name=\"distributionType\">\n" +
" <xs:sequence>\n" +
" <xs:element name=\"deployments\">\n" +
" <xs:complexType>\n" +
" <xs:sequence>\n" +
" <xs:element name=\"deployment\" type=\"deploymentType\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n" +
" </xs:sequence>\n" +
" </xs:complexType>\n" +
" </xs:element>\n" +
" </xs:sequence>\n" +
" </xs:complexType>\n" +
"\n" +
" <xs:complexType name=\"mainTest\">\n" +
" <xs:sequence/>\n" +
" </xs:complexType>\n" +
"</xs:schema>";
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(new StreamSource(new StringReader(sourceXsd)));

Marshaller marshal = cont.createMarshaller();
marshal.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshal.setSchema(schema);
StringWriter resultWriter = new StringWriter();
marshal.marshal(envModel, resultWriter);

String expectedXml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" +
"<environmentModel>\n" +
" <container xsi:type=\"concreteContainerType\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
" <deployments>\n" +
" <deployment>Context-Root</deployment>\n" +
" </deployments>\n" +
" </container>\n" +
" <distribution>\n" +
" <deployments>\n" +
" <deployment xsi:type=\"concreteDeploymentType\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
" <contextRoot>Context-Root</contextRoot>\n" +
" </deployment>\n" +
" </deployments>\n" +
" </distribution>\n" +
"</environmentModel>\n";

Assert.assertEquals(resultWriter.toString(), expectedXml);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (c) 1997, 2019 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

package com.sun.xml.bind.v2.schemagen.xmlidref;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;

/**
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "concreteContainerType")
public class JaxbConcreteContainer extends JaxbContainer {

public static final String ELEMENT_NAME = "concreteContainer";

@Override
public String toString() {
return "JaxbConcreteContainer{" +
"deployments=" + getDeployments() +
'}';
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 1997, 2019 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

package com.sun.xml.bind.v2.schemagen.xmlidref;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;

/**
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "concreteDeploymentType")
public class JaxbConcreteDeployment extends JaxbDeployment {

@Override
public String toString() {
return "JaxbConcreteDeployment{" +
"contextRoot='" + getContextRoot() + '\'' +
'}';
}
}

Loading