From 9838299bbebd7b816d3b5aa37474b41069d98a66 Mon Sep 17 00:00:00 2001 From: Jan Supol Date: Mon, 27 Apr 2020 16:12:18 +0200 Subject: [PATCH] When no JAX-B RI on CP warn and disable WADL Signed-off-by: Jan Supol --- .../message/internal/MessagingBinders.java | 30 +++++-- .../jersey/internal/localization.properties | 3 +- .../jersey/server/wadl/WadlFeature.java | 22 ++++- .../internal/WadlApplicationContextImpl.java | 16 +++- .../server/internal/localization.properties | 3 +- .../src/test/resources/felix.policy | 4 +- .../tests/e2e/common/LoggingFeatureTest.java | 4 +- .../e2e/server/wadl/NoJAXBNoWadlTest.java | 82 +++++++++++++++++++ 8 files changed, 150 insertions(+), 14 deletions(-) create mode 100644 tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/NoJAXBNoWadlTest.java diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/MessagingBinders.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/MessagingBinders.java index 8a665e0218..c01da3d6a6 100644 --- a/core-common/src/main/java/org/glassfish/jersey/message/internal/MessagingBinders.java +++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/MessagingBinders.java @@ -22,6 +22,7 @@ import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.logging.Logger; import javax.ws.rs.RuntimeType; import javax.ws.rs.ext.MessageBodyReader; @@ -30,6 +31,7 @@ import javax.inject.Singleton; import org.glassfish.jersey.CommonProperties; +import org.glassfish.jersey.internal.LocalizationMessages; import org.glassfish.jersey.internal.ServiceFinderBinder; import org.glassfish.jersey.internal.inject.AbstractBinder; import org.glassfish.jersey.internal.util.ReflectionHelper; @@ -45,6 +47,8 @@ */ public final class MessagingBinders { + private static final Logger LOGGER = Logger.getLogger(MessagingBinders.class.getName()); + /** * Prevents instantiation. */ @@ -213,6 +217,22 @@ private void bindToBinder(AbstractBinder binder) { break; } providerBinder.bind(binder, provider); + } else { + switch (provider) { + case DOMSOURCE: + case SAXSOURCE: + case STREAMSOURCE: + LOGGER.warning(LocalizationMessages.DEPENDENT_CLASS_OF_DEFAULT_PROVIDER_NOT_FOUND(provider.className, + "MessageBodyReader<" + provider.className + ">") + ); + break; + case RENDEREDIMAGE: + case SOURCE: + LOGGER.warning(LocalizationMessages.DEPENDENT_CLASS_OF_DEFAULT_PROVIDER_NOT_FOUND(provider.className, + "MessageBodyWriter<" + provider.className + ">") + ); + break; + } } } } @@ -226,14 +246,14 @@ private interface ProviderBinder { void bind(AbstractBinder binder, Provider provider); } - private class DomSourceBinder implements ProviderBinder { + private static class DomSourceBinder implements ProviderBinder { @Override public void bind(AbstractBinder binder, Provider provider) { binder.bind(SourceProvider.DomSourceReader.class).to(MessageBodyReader.class).in(Singleton.class); } } - private class RenderedImageBinder implements ProviderBinder { + private static class RenderedImageBinder implements ProviderBinder { @Override public void bind(AbstractBinder binder, Provider provider) { binder.bind(RenderedImageProvider.class) @@ -241,21 +261,21 @@ public void bind(AbstractBinder binder, Provider provider) { } } - private class SaxSourceBinder implements ProviderBinder { + private static class SaxSourceBinder implements ProviderBinder { @Override public void bind(AbstractBinder binder, Provider provider) { binder.bind(SourceProvider.SaxSourceReader.class).to(MessageBodyReader.class).in(Singleton.class); } } - private class SourceBinder implements ProviderBinder { + private static class SourceBinder implements ProviderBinder { @Override public void bind(AbstractBinder binder, Provider provider) { binder.bind(SourceProvider.SourceWriter.class).to(MessageBodyWriter.class).in(Singleton.class); } } - private class StreamSourceBinder implements ProviderBinder { + private static class StreamSourceBinder implements ProviderBinder { @Override public void bind(AbstractBinder binder, Provider provider) { binder.bind(SourceProvider.StreamSourceReader.class).to(MessageBodyReader.class).in(Singleton.class); diff --git a/core-common/src/main/resources/org/glassfish/jersey/internal/localization.properties b/core-common/src/main/resources/org/glassfish/jersey/internal/localization.properties index 6b56cf58db..285b9de36e 100644 --- a/core-common/src/main/resources/org/glassfish/jersey/internal/localization.properties +++ b/core-common/src/main/resources/org/glassfish/jersey/internal/localization.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2018 Payara Foundation and/or its affiliates. # # This program and the accompanying materials are made available under the @@ -32,6 +32,7 @@ cookie.is.null=Cookie is null. date.is.null=Date is null. dependent.class.of.provider.format.error={0}. A dependent class of the class {1} implementing the provider {2} is malformed. The provider implementation is ignored. Check if the malformed class is part of a stubbed jar that used for compiling only. dependent.class.of.provider.not.found=A dependent class, {0}, of the class {1} implementing the provider {2} is not found. The provider implementation is ignored. +dependent.class.of.default.provider.not.found=A class {0} for a default provider {1} was not found. The provider is not available. entity.tag.is.null=Entity tag is null. error.caught.while.loading.spi.providers=Error caught while loading SPI providers. error.entity.stream.closed=Entity input stream has already been closed. diff --git a/core-server/src/main/java/org/glassfish/jersey/server/wadl/WadlFeature.java b/core-server/src/main/java/org/glassfish/jersey/server/wadl/WadlFeature.java index 29b03fe3fb..1afb644dce 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/wadl/WadlFeature.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/wadl/WadlFeature.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -20,14 +20,19 @@ import javax.ws.rs.core.FeatureContext; import javax.inject.Singleton; +import javax.xml.bind.JAXBException; import org.glassfish.jersey.internal.inject.AbstractBinder; import org.glassfish.jersey.internal.util.PropertiesHelper; import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.internal.LocalizationMessages; import org.glassfish.jersey.server.model.ModelProcessor; import org.glassfish.jersey.server.wadl.internal.WadlApplicationContextImpl; +import org.glassfish.jersey.server.wadl.internal.generators.WadlGeneratorJAXBGrammarGenerator; import org.glassfish.jersey.server.wadl.processor.WadlModelProcessor; +import java.util.logging.Logger; + /** * Feature enabling WADL processing. The feature registers providers and binders needed to enable wadl in the @@ -38,6 +43,8 @@ */ public class WadlFeature implements Feature { + private static final Logger LOGGER = Logger.getLogger(WadlFeature.class.getName()); + @Override public boolean configure(FeatureContext context) { final boolean disabled = PropertiesHelper.isProperty(context.getConfiguration().getProperty(ServerProperties @@ -46,6 +53,11 @@ public boolean configure(FeatureContext context) { return false; } + if (!isJaxB()) { + LOGGER.warning(LocalizationMessages.WADL_FEATURE_DISABLED()); + return false; + } + context.register(WadlModelProcessor.class); context.register(new AbstractBinder() { @Override @@ -56,4 +68,12 @@ protected void configure() { return true; } + + private static boolean isJaxB() { + try { + return null != WadlApplicationContextImpl.getJAXBContextFromWadlGenerator(new WadlGeneratorJAXBGrammarGenerator()); + } catch (JAXBException je) { + return false; + } + } } diff --git a/core-server/src/main/java/org/glassfish/jersey/server/wadl/internal/WadlApplicationContextImpl.java b/core-server/src/main/java/org/glassfish/jersey/server/wadl/internal/WadlApplicationContextImpl.java index 35a6448626..462edec200 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/wadl/internal/WadlApplicationContextImpl.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/wadl/internal/WadlApplicationContextImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -94,7 +94,15 @@ public WadlApplicationContextImpl( // create a temporary generator just to do this one task final WadlGenerator wadlGenerator = wadlGeneratorConfig.createWadlGenerator(injectionManager); - JAXBContext jaxbContextCandidate; + try { + jaxbContext = getJAXBContextFromWadlGenerator(wadlGenerator); + } catch (JAXBException ex) { + throw new ProcessingException(LocalizationMessages.ERROR_WADL_JAXB_CONTEXT(), ex); + } + } + + public static JAXBContext getJAXBContextFromWadlGenerator(WadlGenerator wadlGenerator) throws JAXBException { + JAXBContext jaxbContextCandidate = null; final ClassLoader contextClassLoader = AccessController.doPrivileged(ReflectionHelper.getContextClassLoaderPA()); try { @@ -117,13 +125,13 @@ public WadlApplicationContextImpl( LOGGER.log(Level.FINE, LocalizationMessages.WADL_JAXB_CONTEXT_FALLBACK(), ex); jaxbContextCandidate = JAXBContext.newInstance(wadlGenerator.getRequiredJaxbContextPath()); } catch (final JAXBException innerEx) { - throw new ProcessingException(LocalizationMessages.ERROR_WADL_JAXB_CONTEXT(), ex); + throw ex; } } finally { AccessController.doPrivileged(ReflectionHelper.setContextClassLoaderPA(contextClassLoader)); } - jaxbContext = jaxbContextCandidate; + return jaxbContextCandidate; } @Override diff --git a/core-server/src/main/resources/org/glassfish/jersey/server/internal/localization.properties b/core-server/src/main/resources/org/glassfish/jersey/server/internal/localization.properties index 1c125a7bd2..8629298f82 100644 --- a/core-server/src/main/resources/org/glassfish/jersey/server/internal/localization.properties +++ b/core-server/src/main/resources/org/glassfish/jersey/server/internal/localization.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved. # # This program and the accompanying materials are made available under the # terms of the Eclipse Public License v. 2.0, which is available at @@ -185,6 +185,7 @@ unsupported.uri.injection.type="@Uri"-based injection of "{0}" type is not suppo user.not.authorized=User not authorized. wadl.doc.extended.wadl=This is full WADL including extended resources. To get simplified WADL with users resources only do not use the query parameter {0}. Link: {1} wadl.doc.simple.wadl=This is simplified WADL with user and core resources only. To get full WADL with extended resources use the query parameter {0}. Link: {1} +wadl.feature.disabled=JAXBContext implementation could not be found. WADL feature is disabled. wadl.jaxb.context.fallback=Error creating a JAXBContext for wadl serialization. Trying a fallback solution for osgi environments. wadl.resourcedoc.ambiguous.method.entries=Ambiguous resource documentation detected: \ Unique resource method documentation cannot be found for method %{0}.%{1}%{2}. \ diff --git a/examples/osgi-helloworld-webapp/functional-test/src/test/resources/felix.policy b/examples/osgi-helloworld-webapp/functional-test/src/test/resources/felix.policy index 103cc5206a..d8348f9c35 100644 --- a/examples/osgi-helloworld-webapp/functional-test/src/test/resources/felix.policy +++ b/examples/osgi-helloworld-webapp/functional-test/src/test/resources/felix.policy @@ -1,5 +1,5 @@ // -// Copyright (c) 2014, 2018 Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2014, 2020 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 @@ -13,6 +13,7 @@ allow { [org.osgi.service.condpermadmin.BundleLocationCondition "*System*"] (org allow { [org.osgi.service.condpermadmin.BundleLocationCondition "*additional-bundle*"] (java.security.AllPermission) } "allToAdditional"; allow { [org.osgi.service.condpermadmin.BundleLocationCondition "*javassist*"] (java.security.AllPermission) } "allToJavassist"; allow { [org.osgi.service.condpermadmin.BundleLocationCondition "*jakarta.ws.rs*"] (java.security.AllPermission) } "allToJavaxWsRs"; +allow { [org.osgi.service.condpermadmin.BundleLocationCondition "*jakarta.xml.bind*"] (java.security.AllPermission) } "allToJaxB"; allow { [org.osgi.service.condpermadmin.BundleLocationCondition "*jetty*"] (java.security.AllPermission) } "allToJetty"; allow { [org.osgi.service.condpermadmin.BundleLocationCondition "*hk2*"] (java.security.AllPermission) } "allToHk2"; allow { [org.osgi.service.condpermadmin.BundleLocationCondition "*osgi*"] (java.security.AllPermission) } "allToOsgi"; @@ -36,6 +37,7 @@ allow { [org.osgi.service.condpermadmin.BundleLocationCondition "*jersey-common* allow { [org.osgi.service.condpermadmin.BundleLocationCondition "*jersey-common*"] (java.lang.RuntimePermission "accessClassInPackage.sun.misc") } "accessClassInPackageSunMisc"; allow { [org.osgi.service.condpermadmin.BundleLocationCondition "*jersey-common*"] (java.lang.RuntimePermission "getClassLoader") } "getCLToJerseyCommon"; allow { [org.osgi.service.condpermadmin.BundleLocationCondition "*jersey-common*"] (java.lang.RuntimePermission "modifyThread") } "modifyThreadToJerseyCommon"; +allow { [org.osgi.service.condpermadmin.BundleLocationCondition "*jersey-common*"] (java.lang.RuntimePermission "setContextClassLoader") } "setContextCLToJerseyCommon"; allow { [org.osgi.service.condpermadmin.BundleLocationCondition "*jersey-common*"] (java.util.PropertyPermission "*" "read") } "propReadToJerseyCommon"; allow { [org.osgi.service.condpermadmin.BundleLocationCondition "*jersey-common*"] (java.io.FilePermission "<>" "read,write") } "fileReadToJerseyCommon"; allow { [org.osgi.service.condpermadmin.BundleLocationCondition "*jersey-client*"] (java.security.AllPermission) } "allToJerseyClient"; diff --git a/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/common/LoggingFeatureTest.java b/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/common/LoggingFeatureTest.java index f15e5d8b38..280e94d251 100644 --- a/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/common/LoggingFeatureTest.java +++ b/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/common/LoggingFeatureTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -44,6 +44,7 @@ import org.glassfish.jersey.logging.LoggingFeature; import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.ServerProperties; import org.glassfish.jersey.test.JerseyTest; import org.glassfish.jersey.test.TestProperties; @@ -399,6 +400,7 @@ protected Application configure() { return new ResourceConfig(MyResource.class) .property(LoggingFeature.LOGGING_FEATURE_LOGGER_NAME, LOGGER_NAME) .property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL, "INFO") + .property(ServerProperties.WADL_FEATURE_DISABLE, true) .register(CustomFilter.class); } diff --git a/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/NoJAXBNoWadlTest.java b/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/NoJAXBNoWadlTest.java new file mode 100644 index 0000000000..18fdcb9eb7 --- /dev/null +++ b/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/NoJAXBNoWadlTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.e2e.server.wadl; + +import org.glassfish.jersey.internal.ServiceFinder; +import org.glassfish.jersey.internal.util.JdkVersion; +import org.glassfish.jersey.message.internal.MediaTypes; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.internal.LocalizationMessages; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Response; +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; + +public class NoJAXBNoWadlTest extends JerseyTest { + + private static PrintStream errorStream; + private static OutputStream readableStream = new ByteArrayOutputStream(800); + + @BeforeClass + public static void before() { + errorStream = System.err; + System.setErr(new PrintStream(readableStream)); + } + + @AfterClass + public static void after() { + System.setErr(errorStream); + } + + @Path("dummy") + public static class NoJAXBNoWadlDummyResource { + @PUT + public String put(String put) { + return "OK"; + } + } + + @Override + protected Application configure() { + return new ResourceConfig(NoJAXBNoWadlDummyResource.class); + } + + @Test + public void testOptionsNoWadl() { + final boolean shouldHaveJaxb = JdkVersion.getJdkVersion().getMajor() == 1; + + // Make sure the test does not have JAX-B on a classpath + Assert.assertFalse(ServiceFinder.find("javax.xml.bind.JAXBContext").iterator().hasNext()); + + try (Response r = target("dummy").request(MediaTypes.WADL_TYPE).options()) { + String headers = r.getHeaderString(HttpHeaders.ALLOW); + Assert.assertEquals("OPTIONS,PUT", headers); + } + System.out.println(readableStream.toString()); + Assert.assertEquals(!shouldHaveJaxb, readableStream.toString().contains(LocalizationMessages.WADL_FEATURE_DISABLED())); + } +}