Issue #3801 Jersey-Bean-Validator-fails-to-inject-Weld-managed-beans Signed-off-by: David Matejcek <dmatej@seznam.cz>
diff --git a/ext/bean-validation/pom.xml b/ext/bean-validation/pom.xml index 3ccc26b..e473c17 100644 --- a/ext/bean-validation/pom.xml +++ b/ext/bean-validation/pom.xml
@@ -2,6 +2,7 @@ <!-- Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2018, 2019 Payara Foundation 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 @@ -96,6 +97,16 @@ </exclusion> </exclusions> </dependency> + <dependency> + <groupId>javax.enterprise</groupId> + <artifactId>cdi-api</artifactId> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.ext.cdi</groupId> + <artifactId>jersey-cdi1x</artifactId> + <version>${project.version}</version> + </dependency> + <!-- java-el related dependencies are in scope "provided" in hibernate-validator --> <dependency>
diff --git a/ext/bean-validation/src/main/java/org/glassfish/jersey/server/validation/internal/CompositeInjectingConstraintValidatorFactory.java b/ext/bean-validation/src/main/java/org/glassfish/jersey/server/validation/internal/CompositeInjectingConstraintValidatorFactory.java new file mode 100644 index 0000000..271015d --- /dev/null +++ b/ext/bean-validation/src/main/java/org/glassfish/jersey/server/validation/internal/CompositeInjectingConstraintValidatorFactory.java
@@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018 Payara Foundation 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.server.validation.internal; + +import javax.annotation.PostConstruct; +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorFactory; +import javax.ws.rs.container.ResourceContext; +import javax.ws.rs.core.Context; + +/** + * {@link ConstraintValidatorFactory} implementation that uses {@link InjectingConstraintValidatorFactory} + * by default and fallbacks to {@link HibernateInjectingConstraintValidatorFactory} when the resource + * cannot be found in resource context of Jersey. + * + * @author Mert Caliskan + */ +public class CompositeInjectingConstraintValidatorFactory implements ConstraintValidatorFactory { + + @Context + private ResourceContext resourceContext; + + private InjectingConstraintValidatorFactory jerseyVF; + private HibernateInjectingConstraintValidatorFactory hibernateVF; + + @PostConstruct + void postConstruct() { + jerseyVF = resourceContext.getResource(InjectingConstraintValidatorFactory.class); + hibernateVF = resourceContext.getResource(HibernateInjectingConstraintValidatorFactory.class); + } + + @Override + public <T extends ConstraintValidator<?, ?>> T getInstance(final Class<T> key) { + T jerseyInstance = jerseyVF.getInstance(key); + if (jerseyInstance == null) { + return hibernateVF.getInstance(key); + } + return jerseyInstance; + } + + @Override + public void releaseInstance(final ConstraintValidator<?, ?> instance) { + // NOOP + } +} \ No newline at end of file
diff --git a/ext/bean-validation/src/main/java/org/glassfish/jersey/server/validation/internal/DestructibleBeanInstance.java b/ext/bean-validation/src/main/java/org/glassfish/jersey/server/validation/internal/DestructibleBeanInstance.java new file mode 100644 index 0000000..136a007 --- /dev/null +++ b/ext/bean-validation/src/main/java/org/glassfish/jersey/server/validation/internal/DestructibleBeanInstance.java
@@ -0,0 +1,63 @@ +/* + * Hibernate Validator, declare and validate application constraints + * + * License: Apache License, Version 2.0 + * See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>. + */ +// Portions Copyright [2018] [Payara Foundation and/or its affiliates] + +package org.glassfish.jersey.server.validation.internal; + +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.spi.AnnotatedType; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.InjectionTarget; + +/** + * @author Hardy Ferentschik + */ +public class DestructibleBeanInstance<T> { + private final T instance; + private final InjectionTarget<T> injectionTarget; + + public DestructibleBeanInstance(BeanManager beanManager, Class<T> key) { + this.injectionTarget = createInjectionTarget(beanManager, key); + this.instance = createAndInjectBeans(beanManager, injectionTarget); + } + + @SuppressWarnings("unchecked") + public DestructibleBeanInstance(BeanManager beanManager, T instance) { + this.injectionTarget = createInjectionTarget(beanManager, (Class<T>) instance.getClass()); + injectBeans(beanManager, beanManager.createCreationalContext(null), injectionTarget, instance); + this.instance = instance; + } + + public T getInstance() { + return instance; + } + + public void destroy() { + injectionTarget.preDestroy(instance); + injectionTarget.dispose(instance); + } + + private InjectionTarget<T> createInjectionTarget(BeanManager beanManager, Class<T> type) { + AnnotatedType<T> annotatedType = beanManager.createAnnotatedType(type); + return beanManager.createInjectionTarget(annotatedType); + } + + private static <T> T createAndInjectBeans(BeanManager beanManager, InjectionTarget<T> injectionTarget) { + CreationalContext<T> creationalContext = beanManager.createCreationalContext(null); + + T instance = injectionTarget.produce(creationalContext); + injectBeans(beanManager, creationalContext, injectionTarget, instance); + + return instance; + } + + private static <T> void injectBeans(BeanManager beanManager, CreationalContext<T> creationalContext, + InjectionTarget<T> injectionTarget, T instance) { + injectionTarget.inject(instance, creationalContext); + injectionTarget.postConstruct(instance); + } +} \ No newline at end of file
diff --git a/ext/bean-validation/src/main/java/org/glassfish/jersey/server/validation/internal/HibernateInjectingConstraintValidatorFactory.java b/ext/bean-validation/src/main/java/org/glassfish/jersey/server/validation/internal/HibernateInjectingConstraintValidatorFactory.java new file mode 100644 index 0000000..d0ad811 --- /dev/null +++ b/ext/bean-validation/src/main/java/org/glassfish/jersey/server/validation/internal/HibernateInjectingConstraintValidatorFactory.java
@@ -0,0 +1,52 @@ +/* + * Hibernate Validator, declare and validate application constraints + * + * License: Apache License, Version 2.0 + * See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>. + */ +// Portions Copyright [2018] [Payara Foundation and/or its affiliates] + +package org.glassfish.jersey.server.validation.internal; + +import org.glassfish.jersey.ext.cdi1x.internal.CdiUtil; + +import javax.annotation.PostConstruct; +import javax.enterprise.inject.spi.BeanManager; +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorFactory; +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.Map; + +public class HibernateInjectingConstraintValidatorFactory implements ConstraintValidatorFactory { + // TODO look for something with better performance (HF) + private final Map<Object, DestructibleBeanInstance<?>> constraintValidatorMap = + Collections.synchronizedMap(new IdentityHashMap<Object, DestructibleBeanInstance<?>>()); + + private BeanManager beanManager; + + @PostConstruct + void postConstruct() { + this.beanManager = CdiUtil.getBeanManager(); + } + + @Override + public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) { + DestructibleBeanInstance<T> destructibleBeanInstance = new DestructibleBeanInstance<T>(beanManager, key); + constraintValidatorMap.put(destructibleBeanInstance.getInstance(), destructibleBeanInstance); + return destructibleBeanInstance.getInstance(); + } + + @Override + public void releaseInstance(ConstraintValidator<?, ?> instance) { + DestructibleBeanInstance<?> destructibleBeanInstance = constraintValidatorMap.remove(instance); + // HV-865 (Cleanup is multi threaded and instances can be removed by multiple threads. + // Explicit null check is needed) + if (destructibleBeanInstance != null) { + destructibleBeanInstance.destroy(); + } + } +} + + +
diff --git a/ext/bean-validation/src/main/java/org/glassfish/jersey/server/validation/internal/ValidationBinder.java b/ext/bean-validation/src/main/java/org/glassfish/jersey/server/validation/internal/ValidationBinder.java index 050f920..a5b5d06 100644 --- a/ext/bean-validation/src/main/java/org/glassfish/jersey/server/validation/internal/ValidationBinder.java +++ b/ext/bean-validation/src/main/java/org/glassfish/jersey/server/validation/internal/ValidationBinder.java
@@ -1,5 +1,6 @@ /* * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019 Payara Foundation 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 @@ -256,8 +257,9 @@ private ValidatorContext getDefaultValidatorContext(final ValidateOnExecutionHandler handler) { final ValidatorContext context = factory.usingContext(); - // Default Configuration. - context.constraintValidatorFactory(resourceContext.getResource(InjectingConstraintValidatorFactory.class)); + // Composite Configuration - due to PAYARA-2491 + // https://github.com/payara/Payara/issues/2245 + context.constraintValidatorFactory(resourceContext.getResource(CompositeInjectingConstraintValidatorFactory.class)); // Traversable Resolver. context.traversableResolver(getTraversableResolver(factory.getTraversableResolver(), handler));