diff --git a/api/src/main/java/jakarta/xml/bind/ContextFinder.java b/api/src/main/java/jakarta/xml/bind/ContextFinder.java index 6424a09..12e529c 100644 --- a/api/src/main/java/jakarta/xml/bind/ContextFinder.java +++ b/api/src/main/java/jakarta/xml/bind/ContextFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025 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 @@ -310,7 +310,7 @@ static JAXBContext find(String factoryId, } } if (factoryName != null) { - return newInstance(contextPath, contextPathClasses, factoryName, classLoader, properties); + return newInstance(contextPath, contextPathClasses, factoryName, classLoader, cleanProperties(properties)); } } @@ -354,14 +354,7 @@ static JAXBContext find(Class[] classes, Map properties) throws JA } } if (factoryClassName != null) { - //Providers are not required to understand JAXB_CONTEXT_FACTORY property - //and they must throw a JAXBException if they see it, so we need to remove it - //from properties passed to them - Map props = properties.entrySet() - .stream() - .filter(Predicate.not(e -> JAXBContext.JAXB_CONTEXT_FACTORY.equals(e.getKey()))) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - return newInstance(classes, props, factoryClassName); + return newInstance(classes, cleanProperties(properties), factoryClassName); } } @@ -396,6 +389,16 @@ private static String classNameFromSystemProperties() throws JAXBException { return null; } + private static Map cleanProperties(Map properties) { + // Providers are not required to understand JAXB_CONTEXT_FACTORY property, + // and they must throw a JAXBException if they see it, so we need to remove it + // from properties passed to them + return properties.entrySet() + .stream() + .filter(Predicate.not(e -> JAXBContext.JAXB_CONTEXT_FACTORY.equals(e.getKey()))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + private static String getSystemProperty(String property) { logger.log(Level.FINE, "Checking system property {0}", property); String value = AccessController.doPrivileged(new GetPropertyAction(property)); diff --git a/jaxb-api-test/src/test/java/jakarta/xml/bind/test/JAXBContextTest.java b/jaxb-api-test/src/test/java/jakarta/xml/bind/test/JAXBContextTest.java index 0287bb9..0776575 100644 --- a/jaxb-api-test/src/test/java/jakarta/xml/bind/test/JAXBContextTest.java +++ b/jaxb-api-test/src/test/java/jakarta/xml/bind/test/JAXBContextTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025 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 @@ -25,6 +25,7 @@ import java.nio.file.StandardOpenOption; import java.util.Arrays; import java.util.Collection; +import java.util.Map; import java.util.logging.Logger; import static junit.framework.TestCase.assertTrue; @@ -73,6 +74,9 @@ public class JAXBContextTest { // scenario name - just for logging String scenario; + // properties to pass to JAXBContext#newContext + private Map properties; + // java policy file for testing w/security manager private String expectedFactory; private Class expectedException; @@ -83,70 +87,74 @@ public static Collection configurations() { return Arrays.asList(new Object[][]{ // scenario-name, jaxb.properties, svc, arg1, arg2, system-props // {"scenario-1", FACTORY_ID_LEGACY + "="+PACKAGE_LEGACY+"Valid", null, PACKAGE_LEGACY+"Valid$JAXBContext1", null, null}, - {"scenario-3", FACTORY_ID_LEGACY + "=non.existing.FactoryClass", null, null, jakarta.xml.bind.JAXBException.class, null}, - {"scenario-4", FACTORY_ID_LEGACY + "="+PACKAGE_LEGACY+"Invalid", null, null, jakarta.xml.bind.JAXBException.class, null}, + {"scenario-3", FACTORY_ID_LEGACY + "=non.existing.FactoryClass", null, null, jakarta.xml.bind.JAXBException.class, null, null}, + {"scenario-4", FACTORY_ID_LEGACY + "="+PACKAGE_LEGACY+"Invalid", null, null, jakarta.xml.bind.JAXBException.class, null, null}, // {"scenario-13", FACTORY_ID_LEGACY + "="+PACKAGE_LEGACY+"Valid", PACKAGE_LEGACY+"Valid2", PACKAGE_LEGACY+"Valid$JAXBContext1", null, PACKAGE_LEGACY+"Valid3"}, // {"scenario-1", FACTORY_ID_LEGACY + "="+PACKAGE_SPI+"Valid", null, PACKAGE_SPI+"Valid$JAXBContext1", null, null}, - {"scenario-3", FACTORY_ID_LEGACY + "=non.existing.FactoryClass", null, null, jakarta.xml.bind.JAXBException.class, null}, - {"scenario-4", FACTORY_ID_LEGACY + "="+PACKAGE_SPI+"Invalid", null, null, jakarta.xml.bind.JAXBException.class, null}, + {"scenario-3", FACTORY_ID_LEGACY + "=non.existing.FactoryClass", null, null, jakarta.xml.bind.JAXBException.class, null, null}, + {"scenario-4", FACTORY_ID_LEGACY + "="+PACKAGE_SPI+"Invalid", null, null, jakarta.xml.bind.JAXBException.class, null, null}, // {"scenario-13", FACTORY_ID_LEGACY + "="+PACKAGE_SPI+"Valid", PACKAGE_SPI+"Valid2", PACKAGE_SPI+"Valid$JAXBContext1", null, PACKAGE_SPI+"Valid3"}, // {"scenario-1", FACTORY_ID + "="+PACKAGE_SPI+"Valid", null, PACKAGE_SPI+"Valid$JAXBContext1", null, null}, - {"scenario-3", FACTORY_ID + "=non.existing.FactoryClass", null, null, jakarta.xml.bind.JAXBException.class, null}, - {"scenario-4", FACTORY_ID + "="+PACKAGE_SPI+"Invalid", null, null, jakarta.xml.bind.JAXBException.class, null}, + {"scenario-3", FACTORY_ID + "=non.existing.FactoryClass", null, null, jakarta.xml.bind.JAXBException.class, null, null}, + {"scenario-4", FACTORY_ID + "="+PACKAGE_SPI+"Invalid", null, null, jakarta.xml.bind.JAXBException.class, null, null}, // {"scenario-13", FACTORY_ID + "="+PACKAGE_SPI+"Valid", PACKAGE_SPI+"Valid2", PACKAGE_SPI+"Valid$JAXBContext1", null, PACKAGE_SPI+"Valid3"}, // {"scenario-1", FACTORY_ID + "="+PACKAGE_LEGACY+"Valid", null, PACKAGE_LEGACY+"Valid$JAXBContext1", null, null}, - {"scenario-3", FACTORY_ID + "=non.existing.FactoryClass", null, null, jakarta.xml.bind.JAXBException.class, null}, - {"scenario-4", FACTORY_ID + "="+PACKAGE_LEGACY+"Invalid", null, null, jakarta.xml.bind.JAXBException.class, null}, + {"scenario-3", FACTORY_ID + "=non.existing.FactoryClass", null, null, jakarta.xml.bind.JAXBException.class, null, null}, + {"scenario-4", FACTORY_ID + "="+PACKAGE_LEGACY+"Invalid", null, null, jakarta.xml.bind.JAXBException.class, null, null}, // {"scenario-13", FACTORY_ID + "="+PACKAGE_LEGACY+"Valid", PACKAGE_LEGACY+"Valid2", PACKAGE_LEGACY+"Valid$JAXBContext1", null, PACKAGE_LEGACY+"Valid3"}, - {"scenario-2", "something=AnotherThing", null, null, jakarta.xml.bind.JAXBException.class, null}, + {"scenario-2", "something=AnotherThing", null, null, jakarta.xml.bind.JAXBException.class, null, null}, // service loader - {"scenario-8", null, PACKAGE_SPI+"Valid\n", PACKAGE_SPI+"Valid$JAXBContext1", null, null}, - {"scenario-9", null, PACKAGE_SPI+"Valid", PACKAGE_SPI+"Valid$JAXBContext1", null, null}, - {"scenario-11", null, PACKAGE_SPI+"Invalid", null, jakarta.xml.bind.JAXBException.class, null}, - {"scenario-15", null, PACKAGE_SPI+"Valid", PACKAGE_SPI+"Valid$JAXBContext1", null, null}, + {"scenario-8", null, PACKAGE_SPI+"Valid\n", PACKAGE_SPI+"Valid$JAXBContext1", null, null, null}, + {"scenario-9", null, PACKAGE_SPI+"Valid", PACKAGE_SPI+"Valid$JAXBContext1", null, null, null}, + {"scenario-11", null, PACKAGE_SPI+"Invalid", null, jakarta.xml.bind.JAXBException.class, null, null}, + {"scenario-15", null, PACKAGE_SPI+"Valid", PACKAGE_SPI+"Valid$JAXBContext1", null, null, null}, // service loader - legacy // {"scenario-8 legacy-svc", null, PACKAGE_SPI+"Valid\n", PACKAGE_SPI+"Valid$JAXBContext1", null, null}, // {"scenario-9 legacy-svc", null, PACKAGE_SPI+"Valid", PACKAGE_SPI+"Valid$JAXBContext1", null, null}, - {"scenario-11 legacy-svc", null, PACKAGE_SPI+"Invalid", null, jakarta.xml.bind.JAXBException.class, null}, + {"scenario-11 legacy-svc", null, PACKAGE_SPI+"Invalid", null, jakarta.xml.bind.JAXBException.class, null, null}, // {"scenario-15 legacy-svc", null, PACKAGE_SPI+"Valid", PACKAGE_SPI+"Valid$JAXBContext1", null, null}, // service loader - legacy // {"scenario-8 legacy-svc", null, PACKAGE_LEGACY+"Valid\n", PACKAGE_LEGACY+"Valid$JAXBContext1", null, null}, // {"scenario-9 legacy-svc", null, PACKAGE_LEGACY+"Valid", PACKAGE_LEGACY+"Valid$JAXBContext1", null, null}, - {"scenario-11 legacy-svc", null, PACKAGE_LEGACY+"Invalid", null, jakarta.xml.bind.JAXBException.class, null}, + {"scenario-11 legacy-svc", null, PACKAGE_LEGACY+"Invalid", null, jakarta.xml.bind.JAXBException.class, null, null}, // {"scenario-15 legacy-svc", null, PACKAGE_LEGACY+"Valid", PACKAGE_LEGACY+"Valid$JAXBContext1", null, null}, // system property - {"scenario-5", null, null, PACKAGE_SPI+"Valid$JAXBContext1", null, PACKAGE_SPI+"Valid"}, - {"scenario-7", null, null, null, jakarta.xml.bind.JAXBException.class, PACKAGE_SPI+"Invalid"}, - {"scenario-14", null, PACKAGE_SPI+"Valid2", PACKAGE_SPI+"Valid$JAXBContext1", null, PACKAGE_SPI+"Valid"}, + {"scenario-5", null, null, PACKAGE_SPI+"Valid$JAXBContext1", null, PACKAGE_SPI+"Valid", null}, + {"scenario-7", null, null, null, jakarta.xml.bind.JAXBException.class, PACKAGE_SPI+"Invalid", null}, + {"scenario-14", null, PACKAGE_SPI+"Valid2", PACKAGE_SPI+"Valid$JAXBContext1", null, PACKAGE_SPI+"Valid", null}, + + {"scenario-5", null, null, PACKAGE_LEGACY+"Valid$JAXBContext1", null, PACKAGE_LEGACY+"Valid", null}, + {"scenario-7", null, null, null, jakarta.xml.bind.JAXBException.class, PACKAGE_LEGACY+"Invalid", null}, + {"scenario-14", null, PACKAGE_LEGACY+"Valid2", PACKAGE_LEGACY+"Valid$JAXBContext1", null, PACKAGE_LEGACY+"Valid", null}, + {"scenario-6", null, null, null, jakarta.xml.bind.JAXBException.class, "jaxb.factory.NonExisting", null}, - {"scenario-5", null, null, PACKAGE_LEGACY+"Valid$JAXBContext1", null, PACKAGE_LEGACY+"Valid"}, - {"scenario-7", null, null, null, jakarta.xml.bind.JAXBException.class, PACKAGE_LEGACY+"Invalid"}, - {"scenario-14", null, PACKAGE_LEGACY+"Valid2", PACKAGE_LEGACY+"Valid$JAXBContext1", null, PACKAGE_LEGACY+"Valid"}, - {"scenario-6", null, null, null, jakarta.xml.bind.JAXBException.class, "jaxb.factory.NonExisting"}, + {"scenario-10", null, "jaxb.factory.NonExisting", null, jakarta.xml.bind.JAXBException.class, null, null}, - {"scenario-10", null, "jaxb.factory.NonExisting", null, jakarta.xml.bind.JAXBException.class, null}, + {"scenario-12", null, null, DEFAULT, jakarta.xml.bind.JAXBException.class, null, null}, - {"scenario-12", null, null, DEFAULT, jakarta.xml.bind.JAXBException.class, null}, + // properties + {"scenario-17", null, PACKAGE_SPI+"Valid", PACKAGE_SPI+"Valid$JAXBContext1", null, null, Map.of("jakarta.xml.bind.JAXBContextFactory", PACKAGE_SPI+"Valid")}, }); } - // scenario-name, jaxb.properties, svc, arg1, arg2, system-props + // scenario-name, jaxb.properties, svc, arg1, arg2, system-props, properties public JAXBContextTest( String scenario, String jaxbPropertiesClass, String spiClass, String expectedFactory, Class expectedException, - String systemProperty + String systemProperty, + Map properties ) { // ensure setup may be done ... @@ -161,6 +169,7 @@ public JAXBContextTest( this.scenario = scenario; this.expectedFactory = expectedFactory; this.expectedException = expectedException; + this.properties = properties; if (skipUnsafe && scenario.startsWith("unsafe")) { log("Skipping unsafe scenario:" + scenario); @@ -187,7 +196,20 @@ public void testPath() throws IOException { public void testClasses() throws IOException { logConfigurations(); try { - JAXBContext ctx = JAXBContext.newInstance(new Class[] {A.class}, null); + JAXBContext ctx = JAXBContext.newInstance(new Class[] {A.class}, properties); + handleResult(ctx); + } catch (Throwable throwable) { + handleThrowable(throwable); + } finally { + doFinally(); + } + } + + @Test + public void testClassLoader() throws IOException { + logConfigurations(); + try { + JAXBContext ctx = JAXBContext.newInstance(A.class.getName(), JAXBContextTest.class.getClassLoader(), properties); handleResult(ctx); } catch (Throwable throwable) { handleThrowable(throwable); diff --git a/jaxb-api-test/src/test/java/jaxb/factory/spi/Valid.java b/jaxb-api-test/src/test/java/jaxb/factory/spi/Valid.java index 8602c68..710798e 100644 --- a/jaxb-api-test/src/test/java/jaxb/factory/spi/Valid.java +++ b/jaxb-api-test/src/test/java/jaxb/factory/spi/Valid.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025 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 @@ -24,11 +24,17 @@ public class Valid implements JAXBContextFactory { @Override public JAXBContext createContext(Class[] classesToBeBound, Map properties) throws JAXBException { + if (properties != null && properties.containsKey("jakarta.xml.bind.JAXBContextFactory")) { + throw new JAXBException("property \"jakarta.xml.bind.JAXBContextFactory\" is not supported"); + } return new JAXBContext1(); } @Override public JAXBContext createContext(String contextPath, ClassLoader classLoader, Map properties) throws JAXBException { + if (properties != null && properties.containsKey("jakarta.xml.bind.JAXBContextFactory")) { + throw new JAXBException("property \"jakarta.xml.bind.JAXBContextFactory\" is not supported"); + } return new JAXBContext1(); } diff --git a/jaxb-api-test/src/test/java/jaxb/factory/spi/Valid2.java b/jaxb-api-test/src/test/java/jaxb/factory/spi/Valid2.java index f48de92..866cad2 100644 --- a/jaxb-api-test/src/test/java/jaxb/factory/spi/Valid2.java +++ b/jaxb-api-test/src/test/java/jaxb/factory/spi/Valid2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025 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 @@ -24,11 +24,17 @@ public class Valid2 implements JAXBContextFactory { @Override public JAXBContext createContext(Class[] classesToBeBound, Map properties) throws JAXBException { + if (properties != null && properties.containsKey("jakarta.xml.bind.JAXBContextFactory")) { + throw new JAXBException("property \"jakarta.xml.bind.JAXBContextFactory\" is not supported"); + } return new JAXBContext1(); } @Override public JAXBContext createContext(String contextPath, ClassLoader classLoader, Map properties) throws JAXBException { + if (properties != null && properties.containsKey("jakarta.xml.bind.JAXBContextFactory")) { + throw new JAXBException("property \"jakarta.xml.bind.JAXBContextFactory\" is not supported"); + } return new JAXBContext1(); } diff --git a/jaxb-api-test/src/test/java/jaxb/factory/spi/Valid3.java b/jaxb-api-test/src/test/java/jaxb/factory/spi/Valid3.java index db67496..f480014 100644 --- a/jaxb-api-test/src/test/java/jaxb/factory/spi/Valid3.java +++ b/jaxb-api-test/src/test/java/jaxb/factory/spi/Valid3.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025 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 @@ -24,11 +24,17 @@ public class Valid3 implements JAXBContextFactory { @Override public JAXBContext createContext(Class[] classesToBeBound, Map properties) throws JAXBException { + if (properties != null && properties.containsKey("jakarta.xml.bind.JAXBContextFactory")) { + throw new JAXBException("property \"jakarta.xml.bind.JAXBContextFactory\" is not supported"); + } return new JAXBContext1(); } @Override public JAXBContext createContext(String contextPath, ClassLoader classLoader, Map properties) throws JAXBException { + if (properties != null && properties.containsKey("jakarta.xml.bind.JAXBContextFactory")) { + throw new JAXBException("property \"jakarta.xml.bind.JAXBContextFactory\" is not supported"); + } return new JAXBContext1(); }