You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by rm...@apache.org on 2016/04/21 09:58:59 UTC
tomee git commit: TOMEE-1785 TOMEE-1786 bean validation for jaxrs +
ensuring bval cdi filters actually works
Repository: tomee
Updated Branches:
refs/heads/master ad8b1f92e -> ba36564ba
TOMEE-1785 TOMEE-1786 bean validation for jaxrs + ensuring bval cdi filters actually works
Project: http://git-wip-us.apache.org/repos/asf/tomee/repo
Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/ba36564b
Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/ba36564b
Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/ba36564b
Branch: refs/heads/master
Commit: ba36564badd07fbce0c2ca51864774de28717be5
Parents: ad8b1f9
Author: Romain manni-Bucau <rm...@gmail.com>
Authored: Thu Apr 21 09:58:29 2016 +0200
Committer: Romain manni-Bucau <rm...@gmail.com>
Committed: Thu Apr 21 09:58:29 2016 +0200
----------------------------------------------------------------------
.../openejb/assembler/classic/Assembler.java | 6 +-
.../org/apache/openejb/bval/BValCdiFilter.java | 7 +-
.../apache/openejb/log/logger/Log4j2Logger.java | 13 ++
.../openejb/util/ContainerClassesFilter.java | 1 +
.../server/cxf/rs/CxfRsHttpListener.java | 133 ++++++++++++++-----
.../openejb/server/cxf/rs/AutoBValTest.java | 104 +++++++++++++++
6 files changed, 227 insertions(+), 37 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tomee/blob/ba36564b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
index 619dca4..d576fe6 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
@@ -371,7 +371,11 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
try { // bval jars are optional so do it by reflection
final ClassLoader loader = ParentClassLoaderFinder.Helper.get();
final Object filter = loader.loadClass("org.apache.openejb.bval.BValCdiFilter").newInstance();
- loader.loadClass("org.apache.bval.cdi.BValExtension").getMethod("setAnnotatedTypeFilter").invoke(null, filter);
+ loader.loadClass("org.apache.bval.cdi.BValExtension")
+ .getMethod(
+ "setAnnotatedTypeFilter",
+ loader.loadClass("org.apache.bval.cdi.BValExtension$AnnotatedTypeFilter"))
+ .invoke(null, filter);
} catch (final Throwable th) {
// ignore, bval not compatible or not present
}
http://git-wip-us.apache.org/repos/asf/tomee/blob/ba36564b/container/openejb-core/src/main/java/org/apache/openejb/bval/BValCdiFilter.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/bval/BValCdiFilter.java b/container/openejb-core/src/main/java/org/apache/openejb/bval/BValCdiFilter.java
index 12ca171..a72c73c 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/bval/BValCdiFilter.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/bval/BValCdiFilter.java
@@ -26,6 +26,11 @@ public class BValCdiFilter implements BValExtension.AnnotatedTypeFilter {
@Override
public boolean accept(final AnnotatedType<?> annotatedType) {
- return delegate.accept(annotatedType.getJavaClass().getName());
+ final String name = annotatedType.getJavaClass().getName();
+ if (name.startsWith("org.apache.openejb.")) {
+ final String sub = name.substring("org.apache.openejb.".length());
+ return !sub.startsWith("cdi.transactional") && !sub.startsWith("resource.activemq.jms2");
+ }
+ return delegate.accept(name);
}
}
http://git-wip-us.apache.org/repos/asf/tomee/blob/ba36564b/container/openejb-core/src/main/java/org/apache/openejb/log/logger/Log4j2Logger.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/log/logger/Log4j2Logger.java b/container/openejb-core/src/main/java/org/apache/openejb/log/logger/Log4j2Logger.java
index 60ac420..8ec568c 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/log/logger/Log4j2Logger.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/log/logger/Log4j2Logger.java
@@ -19,6 +19,7 @@ package org.apache.openejb.log.logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.apache.openejb.util.reflection.Reflections;
import java.util.HashMap;
import java.util.Map;
@@ -50,6 +51,18 @@ public class Log4j2Logger extends AbstractDelegatingLogger {
log = LogManager.getLogger(name);
}
+ @Override
+ public void setLevel(final Level newLevel) throws SecurityException {
+ try {
+ Reflections.invokeByReflection(
+ log, "setLevel",
+ new Class<?>[]{org.apache.logging.log4j.Level.class},
+ new Object[]{TO_LOG4J.get(newLevel)});
+ } catch (final Throwable ignore) {
+ // no-op
+ }
+ }
+
public Level getLevel() {
final org.apache.logging.log4j.Level l = log.getLevel();
if (l != null) {
http://git-wip-us.apache.org/repos/asf/tomee/blob/ba36564b/container/openejb-core/src/main/java/org/apache/openejb/util/ContainerClassesFilter.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/util/ContainerClassesFilter.java b/container/openejb-core/src/main/java/org/apache/openejb/util/ContainerClassesFilter.java
index 371e8d8..1cde71f 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/util/ContainerClassesFilter.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/util/ContainerClassesFilter.java
@@ -42,6 +42,7 @@ public class ContainerClassesFilter implements Filter {
final Set<String> excluded = new HashSet<>();
excluded.add("javax");
excluded.add("org.apache.myfaces");
+ excluded.add("org.apache.bval");
excluded.add("org.apache.cxf");
excluded.add("org.apache.oro");
excluded.add("org.apache.ws");
http://git-wip-us.apache.org/repos/asf/tomee/blob/ba36564b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
----------------------------------------------------------------------
diff --git a/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
index 1a8d95e..bd2de16 100644
--- a/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
+++ b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
@@ -23,7 +23,9 @@ import org.apache.cxf.endpoint.EndpointException;
import org.apache.cxf.endpoint.ManagedEndpoint;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.endpoint.ServerImpl;
+import org.apache.cxf.feature.Feature;
import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.interceptor.Interceptor;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.JAXRSServiceImpl;
import org.apache.cxf.jaxrs.ext.ResourceComparator;
@@ -41,6 +43,10 @@ import org.apache.cxf.message.Message;
import org.apache.cxf.service.invoker.Invoker;
import org.apache.cxf.transport.DestinationFactory;
import org.apache.cxf.transport.servlet.BaseUrlHelper;
+import org.apache.cxf.validation.BeanValidationFeature;
+import org.apache.cxf.validation.BeanValidationInInterceptor;
+import org.apache.cxf.validation.BeanValidationOutInterceptor;
+import org.apache.cxf.validation.BeanValidationProvider;
import org.apache.johnzon.jaxrs.WadlDocumentMessageBodyWriter;
import org.apache.openejb.AppContext;
import org.apache.openejb.BeanContext;
@@ -146,6 +152,10 @@ public class CxfRsHttpListener implements RsHttpListener {
private static final Map<String, String> STATIC_CONTENT_TYPES;
private static final String[] DEFAULT_WELCOME_FILES = new String[]{"/index.html", "/index.htm"};
+ // we have proxies etc so we can't really give it to cxf properly,
+ // bval impl supports it (message just uses Object instead of the real instance)
+ private static final Object FAKE_SERVICE_OBJECT = new Object();
+
private final DestinationFactory transportFactory;
private final String wildcard;
private HttpDestination destination;
@@ -321,7 +331,7 @@ public class CxfRsHttpListener implements RsHttpListener {
final Collection<Object> additionalProviders,
final ServiceConfiguration configuration) {
deploy(contextRoot, loadedClazz, fullContext, new OpenEJBPerRequestPojoResourceProvider(loader, loadedClazz, injections, context, owbCtx),
- null, app, null, additionalProviders, configuration, owbCtx);
+ null, app, null, additionalProviders, configuration, owbCtx);
}
@Override
@@ -334,8 +344,8 @@ public class CxfRsHttpListener implements RsHttpListener {
final Object proxy = ProxyEJB.subclassProxy(beanContext);
deploy(contextRoot, beanContext.getBeanClass(), fullContext, new NoopResourceProvider(beanContext.getBeanClass(), proxy),
- proxy, null, new OpenEJBEJBInvoker(Collections.singleton(beanContext)), additionalProviders, configuration,
- beanContext.getWebBeansContext());
+ proxy, null, new OpenEJBEJBInvoker(Collections.singleton(beanContext)), additionalProviders, configuration,
+ beanContext.getWebBeansContext());
}
private void deploy(final String contextRoot, final Class<?> clazz, final String address, final ResourceProvider rp, final Object serviceBean,
@@ -471,10 +481,10 @@ public class CxfRsHttpListener implements RsHttpListener {
private static boolean shouldSkipProvider(final String name) {
return "false".equalsIgnoreCase(SystemInstance.get().getProperty(name + ".activated", "true"))
- || name.startsWith("org.apache.wink.common.internal.");
+ || name.startsWith("org.apache.wink.common.internal.");
}
- private static void addMandatoryProviders(final Collection<Object> instances) {
+ private static void addMandatoryProviders(final Collection<Object> instances, final ServiceConfiguration serviceConfiguration) {
if (!shouldSkipProvider(WadlDocumentMessageBodyWriter.class.getName())) {
instances.add(new WadlDocumentMessageBodyWriter());
}
@@ -483,6 +493,19 @@ public class CxfRsHttpListener implements RsHttpListener {
}
if (!shouldSkipProvider(ValidationExceptionMapper.class.getName())) {
instances.add(new ValidationExceptionMapper());
+ final String level = SystemInstance.get()
+ .getProperty(
+ "openejb.cxf.rs.bval.log.level",
+ serviceConfiguration.getProperties().getProperty(CXF_JAXRS_PREFIX + "bval.log.level"));
+ if (level != null) {
+ try {
+ LogUtils.getL7dLogger(ValidationExceptionMapper.class).setLevel(Level.parse(level));
+ } catch (final UnsupportedOperationException uoe) {
+ LOGGER.warning("Can't set level " + level + " on " +
+ "org.apache.cxf.jaxrs.validation.ValidationExceptionMapper logger, " +
+ "please configure it in your logging framework.");
+ }
+ }
}
}
@@ -554,7 +577,7 @@ public class CxfRsHttpListener implements RsHttpListener {
factory.setResourceProvider(clazz, new NoopResourceProvider(restServiceInfo.context.getBeanClass(), proxy));
} else {
factory.setResourceProvider(clazz, new OpenEJBPerRequestPojoResourceProvider(
- classLoader, clazz, injections, context, owbCtx));
+ classLoader, clazz, injections, context, owbCtx));
}
}
}
@@ -656,9 +679,9 @@ public class CxfRsHttpListener implements RsHttpListener {
for (final ProviderInfo<?> o : values) { // using getName to not suppose any classloader setup
final String name = o.getResourceClass().getName();
if ("org.apache.johnzon.jaxrs.ConfigurableJohnzonProvider".equals(name)
- || "org.apache.johnzon.jaxrs.jsonb.jaxrs.JsonbJaxrsProvider".equals(name)
- // contains in case of proxying
- || name.contains("com.fasterxml.jackson.jaxrs.json")) {
+ || "org.apache.johnzon.jaxrs.jsonb.jaxrs.JsonbJaxrsProvider".equals(name)
+ // contains in case of proxying
+ || name.contains("com.fasterxml.jackson.jaxrs.json")) {
customJsonProvider = true;
break; // cause we only handle json for now
}
@@ -669,7 +692,7 @@ public class CxfRsHttpListener implements RsHttpListener {
while (it.hasNext()) {
final String name = it.next().getResourceClass().getName();
if ("org.apache.johnzon.jaxrs.JohnzonProvider".equals(name) ||
- "org.apache.openejb.server.cxf.rs.CxfRSService$TomEEJohnzonProvider".equals(name)) {
+ "org.apache.openejb.server.cxf.rs.CxfRSService$TomEEJohnzonProvider".equals(name)) {
it.remove();
break;
}
@@ -777,8 +800,8 @@ public class CxfRsHttpListener implements RsHttpListener {
// effective logging
LOGGER.info("REST Application: " + Logs.forceLength(prefix, addressSize, true) + " -> " +
- (InternalApplication.class.isInstance(application) && InternalApplication.class.cast(application).getOriginal() != null ?
- InternalApplication.class.cast(application).getOriginal() : application));
+ (InternalApplication.class.isInstance(application) && InternalApplication.class.cast(application).getOriginal() != null ?
+ InternalApplication.class.cast(application).getOriginal() : application));
Collections.sort(resourcesToLog);
@@ -786,29 +809,29 @@ public class CxfRsHttpListener implements RsHttpListener {
// Init and register MBeans
final ObjectNameBuilder jmxName = new ObjectNameBuilder("openejb.management")
- .set("j2eeType", "JAX-RS")
- .set("J2EEServer", "openejb")
- .set("J2EEApplication", base)
- .set("EndpointType", resource.type)
- .set("name", resource.classname);
+ .set("j2eeType", "JAX-RS")
+ .set("J2EEServer", "openejb")
+ .set("J2EEApplication", base)
+ .set("EndpointType", resource.type)
+ .set("name", resource.classname);
final ObjectName jmxObjectName = jmxName.build();
LocalMBeanServer.registerDynamicWrapperSilently(
- new RestServiceMBean(resource),
- jmxObjectName);
+ new RestServiceMBean(resource),
+ jmxObjectName);
jmxNames.add(jmxObjectName);
LOGGER.info(" Service URI: "
- + Logs.forceLength(resource.address, addressSize, true) + " -> "
- + Logs.forceLength(resource.type, 4, false) + " "
- + Logs.forceLength(resource.classname, classSize, true));
+ + Logs.forceLength(resource.address, addressSize, true) + " -> "
+ + Logs.forceLength(resource.type, 4, false) + " "
+ + Logs.forceLength(resource.classname, classSize, true));
for (final Logs.LogOperationEndpointInfo log : resource.operations) {
LOGGER.info(" "
- + Logs.forceLength(log.http, resource.methodSize, false) + " "
- + Logs.forceLength(log.address, addressSize, true) + " -> "
- + Logs.forceLength(log.method, resource.methodStrSize, true));
+ + Logs.forceLength(log.http, resource.methodSize, false) + " "
+ + Logs.forceLength(log.address, addressSize, true) + " -> "
+ + Logs.forceLength(log.method, resource.methodStrSize, true));
}
resource.operations.clear();
@@ -844,6 +867,46 @@ public class CxfRsHttpListener implements RsHttpListener {
}
CxfUtil.configureEndpoint(factory, serviceConfiguration, CXF_JAXRS_PREFIX);
+ // activate bval
+ boolean bvalActive = Boolean.parseBoolean(
+ SystemInstance.get().getProperty("openejb.cxf.rs.bval.active",
+ serviceConfiguration.getProperties().getProperty(CXF_JAXRS_PREFIX + "bval.active", "true")));
+ if (factory.getFeatures() == null && bvalActive) {
+ factory.setFeatures(new ArrayList<Feature>());
+ } else if (bvalActive) { // check we should activate it and user didn't configure it
+ for (final Feature f : factory.getFeatures()) {
+ if (BeanValidationFeature.class.isInstance(f)) {
+ bvalActive = false;
+ break;
+ }
+ }
+ for (final Interceptor<?> i : factory.getInInterceptors()) {
+ if (BeanValidationInInterceptor.class.isInstance(i)) {
+ bvalActive = false;
+ break;
+ }
+ }
+ for (final Interceptor<?> i : factory.getOutInterceptors()) {
+ if (BeanValidationOutInterceptor.class.isInstance(i)) {
+ bvalActive = false;
+ break;
+ }
+ }
+ }
+ if (bvalActive) {
+ final BeanValidationProvider provider = new BeanValidationProvider();
+
+ final BeanValidationInInterceptor in = new BeanValidationInInterceptor();
+ in.setProvider(provider);
+ in.setServiceObject(FAKE_SERVICE_OBJECT);
+ factory.getInInterceptors().add(in);
+
+ final BeanValidationOutInterceptor out = new BeanValidationOutInterceptor();
+ out.setProvider(provider);
+ out.setServiceObject(FAKE_SERVICE_OBJECT);
+ factory.getOutInterceptors().add(out);
+ }
+
final Collection<ServiceInfo> services = serviceConfiguration.getAvailableServices();
final String staticSubresourceResolution = serviceConfiguration.getProperties().getProperty(CXF_JAXRS_PREFIX + STATIC_SUB_RESOURCE_RESOLUTION_KEY);
@@ -858,7 +921,7 @@ public class CxfRsHttpListener implements RsHttpListener {
ResourceComparator instance = (ResourceComparator) ServiceInfos.resolve(services, resourceComparator);
if (instance == null) {
instance = (ResourceComparator) Thread.currentThread().getContextClassLoader()
- .loadClass(resourceComparator).newInstance();
+ .loadClass(resourceComparator).newInstance();
}
factory.setResourceComparator(instance);
} catch (final Exception e) {
@@ -920,11 +983,11 @@ public class CxfRsHttpListener implements RsHttpListener {
}
if (!ignoreAutoProviders) {
- addMandatoryProviders(providers);
+ addMandatoryProviders(providers, serviceConfiguration);
}
SystemInstance.get().fireEvent(new ExtensionProviderRegistration(
- AppFinder.findAppContextOrWeb(Thread.currentThread().getContextClassLoader(), AppFinder.AppContextTransformer.INSTANCE), providers));
+ AppFinder.findAppContextOrWeb(Thread.currentThread().getContextClassLoader(), AppFinder.AppContextTransformer.INSTANCE), providers));
if (!providers.isEmpty()) {
factory.setProviders(providers);
@@ -934,7 +997,7 @@ public class CxfRsHttpListener implements RsHttpListener {
private Comparator<?> findProviderComparator(final ServiceConfiguration serviceConfiguration, final WebBeansContext ctx) {
final String comparatorKey = CXF_JAXRS_PREFIX + "provider-comparator";
final String comparatorClass = serviceConfiguration.getProperties()
- .getProperty(comparatorKey, SystemInstance.get().getProperty(comparatorKey));
+ .getProperty(comparatorKey, SystemInstance.get().getProperty(comparatorKey));
Comparator<Object> comparator = null;
if (comparatorClass == null) {
@@ -1026,8 +1089,8 @@ public class CxfRsHttpListener implements RsHttpListener {
final boolean loadersNotNull = classLoader1 != null && classLoader2 != null;
if (classLoader1 != classLoader2
- && loadersNotNull
- && !classLoader1.equals(classLoader2) && !classLoader2.equals(classLoader1)) {
+ && loadersNotNull
+ && !classLoader1.equals(classLoader2) && !classLoader2.equals(classLoader1)) {
if (isParent(classLoader1, classLoader2)) {
return 1;
}
@@ -1042,9 +1105,9 @@ public class CxfRsHttpListener implements RsHttpListener {
if (MessageBodyWriter.class.isInstance(o1.getProvider())) {
final List<MediaType> types1 =
- JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderProduceTypes(MessageBodyWriter.class.cast(o1.getProvider())), JAXRSUtils.MEDIA_TYPE_QS_PARAM);
+ JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderProduceTypes(MessageBodyWriter.class.cast(o1.getProvider())), JAXRSUtils.MEDIA_TYPE_QS_PARAM);
final List<MediaType> types2 =
- JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderProduceTypes(MessageBodyWriter.class.cast(o2.getProvider())), JAXRSUtils.MEDIA_TYPE_QS_PARAM);
+ JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderProduceTypes(MessageBodyWriter.class.cast(o2.getProvider())), JAXRSUtils.MEDIA_TYPE_QS_PARAM);
if (types1.contains(MediaType.WILDCARD_TYPE) && !types2.contains(MediaType.WILDCARD_TYPE)) {
return 1;
@@ -1059,9 +1122,9 @@ public class CxfRsHttpListener implements RsHttpListener {
}
} else if (MessageBodyReader.class.isInstance(o1.getProvider())) { // else is not super good but using both is not sa well so let it be for now
final List<MediaType> types1 =
- JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderConsumeTypes(MessageBodyReader.class.cast(o1.getProvider())), null);
+ JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderConsumeTypes(MessageBodyReader.class.cast(o1.getProvider())), null);
final List<MediaType> types2 =
- JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderConsumeTypes(MessageBodyReader.class.cast(o2.getProvider())), null);
+ JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderConsumeTypes(MessageBodyReader.class.cast(o2.getProvider())), null);
if (types1.contains(MediaType.WILDCARD_TYPE) && !types2.contains(MediaType.WILDCARD_TYPE)) {
return 1;
http://git-wip-us.apache.org/repos/asf/tomee/blob/ba36564b/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/AutoBValTest.java
----------------------------------------------------------------------
diff --git a/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/AutoBValTest.java b/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/AutoBValTest.java
new file mode 100644
index 0000000..d76fbc7
--- /dev/null
+++ b/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/AutoBValTest.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openejb.server.cxf.rs;
+
+import org.apache.openejb.junit.ApplicationComposer;
+import org.apache.openejb.testing.Classes;
+import org.apache.openejb.testing.ContainerProperties;
+import org.apache.openejb.testing.EnableServices;
+import org.apache.openejb.testing.RandomPort;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.net.URL;
+
+import static org.junit.Assert.assertEquals;
+
+@EnableServices("jaxrs")
+@Classes(cdi = true, innerClassesAsBean = true)
+@RunWith(ApplicationComposer.class)
+@ContainerProperties(@ContainerProperties.Property(name = "openejb.cxf.rs.bval.log.level", value = "INFO"))
+public class AutoBValTest {
+ @RandomPort("http")
+ private URL base;
+
+ @Test
+ public void passing() {
+ final Payload payload = new Payload();
+ payload.setName("ok");
+ assertEquals(
+ "ok",
+ ClientBuilder.newClient().target(base.toExternalForm()).path("openejb/test").request(MediaType.APPLICATION_JSON_TYPE)
+ .post(Entity.entity(payload, MediaType.APPLICATION_JSON_TYPE), Payload.class)
+ .getName());
+ }
+
+ @Test
+ public void inFailing() {
+ final Payload payload = new Payload();
+ assertEquals(
+ Response.Status.BAD_REQUEST.getStatusCode(), // thanks to the mapper
+ ClientBuilder.newClient().target(base.toExternalForm()).path("openejb/test").request(MediaType.APPLICATION_JSON_TYPE)
+ .post(Entity.entity(payload, MediaType.APPLICATION_JSON_TYPE)).getStatus());
+ }
+
+ @Test
+ public void outFailing() {
+ final Payload payload = new Payload();
+ payload.setName("empty");
+ assertEquals(
+ Response.Status.BAD_REQUEST.getStatusCode(), // thanks to the mapper
+ ClientBuilder.newClient().target(base.toExternalForm()).path("openejb/test").request(MediaType.APPLICATION_JSON_TYPE)
+ .post(Entity.entity(payload, MediaType.APPLICATION_JSON_TYPE)).getStatus());
+ }
+
+ @Path("test")
+ public static class ValidateMe {
+ @POST
+ @Valid
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Payload get(@Valid final Payload in) {
+ final Payload payload = new Payload();
+ payload.setName("empty".equals(in.name) ? null : in.name);
+ return payload;
+ }
+ }
+
+ public static class Payload {
+ @NotNull
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+ }
+}