You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwebbeans.apache.org by jl...@apache.org on 2025/05/15 17:59:34 UTC
(openwebbeans) branch owb_2.0.x updated (3feacc662 -> ab45ce695)
This is an automated email from the ASF dual-hosted git repository.
jlmonteiro pushed a change to branch owb_2.0.x
in repository https://gitbox.apache.org/repos/asf/openwebbeans.git
from 3feacc662 Merge pull request #127 from jgallimore/owb_2.0.x-owb-cdi-junit
new cdc9a5793 fix: maven dependency to Gradle not found and NPE in previous plugin version
new f93bfea82 fix(#OWB-1450): remove non working cache on proxies per AT
new ab45ce695 fix(#OWB-1450): Interceptor proxy memory leak. Add caching at an higher level
The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
pom.xml | 2 +-
webbeans-gradle/pom.xml | 4 +
.../TrackingAnnotatedTypeConfiguratorImpl.java | 522 +++++++++++++++++++++
.../container/InterceptionFactoryImpl.java | 120 +++--
.../webbeans/portable/AnnotatedTypeImpl.java | 2 +-
.../proxy/InterceptorDecoratorProxyFactory.java | 13 -
.../org/apache/webbeans/util/WebBeansUtil.java | 8 +
.../TrackingAnnotatedTypeConfiguratorImplTest.java | 251 ++++++++++
.../InterceptorDecoratorProxyFactoryTest.java | 74 ++-
9 files changed, 949 insertions(+), 47 deletions(-)
create mode 100644 webbeans-impl/src/main/java/org/apache/webbeans/configurator/TrackingAnnotatedTypeConfiguratorImpl.java
create mode 100644 webbeans-impl/src/test/java/org/apache/webbeans/configurator/TrackingAnnotatedTypeConfiguratorImplTest.java
(openwebbeans) 02/03: fix(#OWB-1450): remove non working cache on proxies per AT
Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
jlmonteiro pushed a commit to branch owb_2.0.x
in repository https://gitbox.apache.org/repos/asf/openwebbeans.git
commit f93bfea822251c851f0220169ebf65279729ac51
Author: Jean-Louis Monteiro <jl...@tomitribe.com>
AuthorDate: Wed May 14 13:54:05 2025 +0200
fix(#OWB-1450): remove non working cache on proxies per AT
---
.../apache/webbeans/container/InterceptionFactoryImpl.java | 2 +-
.../webbeans/proxy/InterceptorDecoratorProxyFactory.java | 13 -------------
2 files changed, 1 insertion(+), 14 deletions(-)
diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/container/InterceptionFactoryImpl.java b/webbeans-impl/src/main/java/org/apache/webbeans/container/InterceptionFactoryImpl.java
index 8dbbf214e..3064902d3 100644
--- a/webbeans-impl/src/main/java/org/apache/webbeans/container/InterceptionFactoryImpl.java
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/container/InterceptionFactoryImpl.java
@@ -83,7 +83,7 @@ public class InterceptionFactoryImpl<T> implements InterceptionFactory<T> /*todo
InterceptorResolutionService.BeanInterceptorInfo interceptorInfo =
context.getInterceptorResolutionService()
.calculateInterceptorInfo(newAnnotatedType.getTypeClosure(), qualifiers, newAnnotatedType, !ignoreFinals);
- Class<T> subClass = factory.getCachedProxyClass(interceptorInfo, newAnnotatedType, classLoader);
+ Class<T> subClass = factory.createProxyClass(interceptorInfo, newAnnotatedType, classLoader);
Map<Interceptor<?>,Object> interceptorInstances = context.getInterceptorResolutionService()
.createInterceptorInstances(interceptorInfo, creationalContext);
diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/proxy/InterceptorDecoratorProxyFactory.java b/webbeans-impl/src/main/java/org/apache/webbeans/proxy/InterceptorDecoratorProxyFactory.java
index 5b8f8210f..3175a6770 100644
--- a/webbeans-impl/src/main/java/org/apache/webbeans/proxy/InterceptorDecoratorProxyFactory.java
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/proxy/InterceptorDecoratorProxyFactory.java
@@ -67,7 +67,6 @@ public class InterceptorDecoratorProxyFactory extends AbstractProxyFactory
* We need this to prevent filling up the ClassLoaders by
*/
private ConcurrentMap<Bean<?>, Class<?>> cachedProxyClasses = new ConcurrentHashMap<>();
- private ConcurrentMap<AnnotatedType<?>, Class<?>> cachedProxyClassesByAt = new ConcurrentHashMap<>();
public InterceptorDecoratorProxyFactory(WebBeansContext webBeansContext)
@@ -191,7 +190,6 @@ public class InterceptorDecoratorProxyFactory extends AbstractProxyFactory
Class<T> proxyClass = createProxyClass(
classLoader, at.getJavaClass(),
intercepted.toArray(new Method[intercepted.size()]), others.toArray(new Method[others.size()]));
- cachedProxyClassesByAt.put(at, proxyClass);
return proxyClass;
}
@@ -221,17 +219,6 @@ public class InterceptorDecoratorProxyFactory extends AbstractProxyFactory
return clazz;
}
- public <T> Class<T> getCachedProxyClass(InterceptorResolutionService.BeanInterceptorInfo interceptorInfo,
- AnnotatedType<T> at, ClassLoader classLoader)
- {
- Class<T> value = (Class<T>) cachedProxyClassesByAt.get(at);
- if (value == null)
- {
- value = createProxyClass(interceptorInfo, at, classLoader);
- }
- return value;
- }
-
public <T> Class<T> getCachedProxyClass(Bean<T> bean)
{
return (Class<T>) cachedProxyClasses.get(bean);
(openwebbeans) 01/03: fix: maven dependency to Gradle not found and NPE in previous plugin version
Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
jlmonteiro pushed a commit to branch owb_2.0.x
in repository https://gitbox.apache.org/repos/asf/openwebbeans.git
commit cdc9a57938125e47cf586c5978b0d0aff0f171c5
Author: Jean-Louis Monteiro <jl...@tomitribe.com>
AuthorDate: Fri May 9 15:21:52 2025 +0200
fix: maven dependency to Gradle not found and NPE in previous plugin version
---
pom.xml | 2 +-
webbeans-gradle/pom.xml | 4 ++++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 1f7dcc03d..00c01c65d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -298,7 +298,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-remote-resources-plugin</artifactId>
- <version>1.5</version>
+ <version>3.3.0</version>
<executions>
<execution>
<goals>
diff --git a/webbeans-gradle/pom.xml b/webbeans-gradle/pom.xml
index 428480832..5c528d67e 100644
--- a/webbeans-gradle/pom.xml
+++ b/webbeans-gradle/pom.xml
@@ -70,5 +70,9 @@
<id>gradle-m2</id>
<url>https://plugins.gradle.org/m2/</url>
</repository>
+ <repository>
+ <id>gradle-releases</id>
+ <url>https://repo.gradle.org/gradle/libs-releases/</url>
+ </repository>
</repositories>
</project>
(openwebbeans) 03/03: fix(#OWB-1450): Interceptor proxy memory leak. Add caching at an higher level
Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
jlmonteiro pushed a commit to branch owb_2.0.x
in repository https://gitbox.apache.org/repos/asf/openwebbeans.git
commit ab45ce695d8e87191132db0a6f2f4d60e5abb7e1
Author: Jean-Louis Monteiro <jl...@tomitribe.com>
AuthorDate: Wed May 14 11:51:07 2025 +0200
fix(#OWB-1450): Interceptor proxy memory leak. Add caching at an higher level
---
.../TrackingAnnotatedTypeConfiguratorImpl.java | 522 +++++++++++++++++++++
.../container/InterceptionFactoryImpl.java | 120 +++--
.../webbeans/portable/AnnotatedTypeImpl.java | 2 +-
.../org/apache/webbeans/util/WebBeansUtil.java | 8 +
.../TrackingAnnotatedTypeConfiguratorImplTest.java | 251 ++++++++++
.../InterceptorDecoratorProxyFactoryTest.java | 74 ++-
6 files changed, 944 insertions(+), 33 deletions(-)
diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/configurator/TrackingAnnotatedTypeConfiguratorImpl.java b/webbeans-impl/src/main/java/org/apache/webbeans/configurator/TrackingAnnotatedTypeConfiguratorImpl.java
new file mode 100644
index 000000000..4826c199d
--- /dev/null
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/configurator/TrackingAnnotatedTypeConfiguratorImpl.java
@@ -0,0 +1,522 @@
+/*
+ * 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.webbeans.configurator;
+
+import javax.enterprise.inject.spi.AnnotatedParameter;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.AnnotatedConstructor;
+import javax.enterprise.inject.spi.AnnotatedField;
+import javax.enterprise.inject.spi.AnnotatedMethod;
+import javax.enterprise.inject.spi.configurator.AnnotatedConstructorConfigurator;
+import javax.enterprise.inject.spi.configurator.AnnotatedFieldConfigurator;
+import javax.enterprise.inject.spi.configurator.AnnotatedMethodConfigurator;
+import javax.enterprise.inject.spi.configurator.AnnotatedParameterConfigurator;
+import javax.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator;
+import org.apache.webbeans.portable.AnnotatedTypeImpl;
+
+import java.lang.annotation.Annotation;
+import java.util.*;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class TrackingAnnotatedTypeConfiguratorImpl<T> implements AnnotatedTypeConfigurator<T>
+{
+
+ private final AnnotatedTypeConfiguratorImpl<T> delegate;
+ private final List<String> actions = new ArrayList<>();
+
+ public TrackingAnnotatedTypeConfiguratorImpl(final AnnotatedTypeConfiguratorImpl<T> delegate)
+ {
+ this.delegate = delegate;
+ }
+
+ public String getPassivationId()
+ {
+ return actions.stream().collect(Collectors.joining(">>"));
+ }
+
+ @Override
+ public final boolean equals(final Object o)
+ {
+ if (!(o instanceof TrackingAnnotatedTypeConfiguratorImpl))
+ {
+ return false;
+ }
+
+ final TrackingAnnotatedTypeConfiguratorImpl<?> that = (TrackingAnnotatedTypeConfiguratorImpl<?>) o;
+ return getPassivationId().equals(that.getPassivationId());
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return getPassivationId().hashCode();
+ }
+
+ @Override
+ public AnnotatedType<T> getAnnotated()
+ {
+ return delegate.getAnnotated();
+ }
+
+ @Override
+ public AnnotatedTypeConfigurator<T> add(Annotation annotation)
+ {
+ actions.add("+@" + annotation.annotationType());
+ delegate.add(annotation);
+ return this;
+ }
+
+ @Override
+ public AnnotatedTypeConfigurator<T> remove(Predicate<Annotation> predicate)
+ {
+ delegate.remove(a ->
+ {
+ if (predicate.test((Annotation) a))
+ {
+ actions.add("-@" + ((Annotation) a).annotationType());
+ return true;
+ }
+ return false;
+ });
+ return this;
+ }
+
+ @Override
+ public AnnotatedTypeConfigurator<T> removeAll()
+ {
+ actions.add("--");
+ delegate.removeAll();
+ return this;
+ }
+
+ @Override
+ public Set<AnnotatedMethodConfigurator<? super T>> methods()
+ {
+ return delegate.methods().stream()
+ .map(m -> new TrackingAnnotatedMethodConfiguratorImpl<>(m, actions))
+ .collect(Collectors.toSet());
+ }
+
+ @Override
+ public Stream<AnnotatedMethodConfigurator<? super T>> filterMethods(Predicate<AnnotatedMethod<? super T>> predicate)
+ {
+ return delegate.filterMethods(a ->
+ {
+ if (predicate.test(a))
+ {
+ actions.add("-m@" + a);
+ return true;
+ }
+ return false;
+ });
+ }
+
+ @Override
+ public Set<AnnotatedFieldConfigurator<? super T>> fields()
+ {
+ return delegate.fields().stream()
+ .map(f -> new TrackingAnnotatedFieldConfiguratorImpl<>(f, actions))
+ .collect(Collectors.toSet());
+ }
+
+ @Override
+ public Stream<AnnotatedFieldConfigurator<? super T>> filterFields(Predicate<AnnotatedField<? super T>> predicate)
+ {
+ return delegate.filterFields(a ->
+ {
+ if (predicate.test(a))
+ {
+ actions.add("-f@" + a);
+ return true;
+ }
+ return false;
+ });
+ }
+
+ @Override
+ public Set<AnnotatedConstructorConfigurator<T>> constructors()
+ {
+ return delegate.constructors().stream()
+ .map(c -> new TrackingAnnotatedConstructorConfiguratorImpl<>(c, actions))
+ .collect(Collectors.toSet());
+ }
+
+ @Override
+ public Stream<AnnotatedConstructorConfigurator<T>> filterConstructors(Predicate<AnnotatedConstructor<T>> predicate)
+ {
+ return delegate.filterConstructors(a ->
+ {
+ if (predicate.test(a))
+ {
+ actions.add("-c@" + a);
+ return true;
+ }
+ return false;
+ });
+ }
+
+
+ public AnnotatedTypeImpl<T> getNewAnnotatedType()
+ {
+ return delegate.getNewAnnotatedType();
+ }
+
+ public static class TrackingAnnotatedFieldConfiguratorImpl<T> implements AnnotatedFieldConfigurator<T>
+ {
+ private final AnnotatedFieldConfigurator<T> delegate;
+ private final List<String> actions;
+
+ public TrackingAnnotatedFieldConfiguratorImpl(final AnnotatedFieldConfigurator<T> delegate,
+ final List<String> actions)
+ {
+ this.delegate = delegate;
+ this.actions = actions;
+ this.actions.add("\n\t");
+ }
+
+ @Override
+ public final boolean equals(final Object o)
+ {
+ if (!(o instanceof TrackingAnnotatedFieldConfiguratorImpl))
+ {
+ return false;
+ }
+
+ final TrackingAnnotatedFieldConfiguratorImpl<?> that = (TrackingAnnotatedFieldConfiguratorImpl<?>) o;
+ return delegate.equals(that.delegate);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return delegate.hashCode();
+ }
+
+ @Override
+ public String toString()
+ {
+ return "TrackingField(" + delegate + ")";
+ }
+
+ @Override
+ public AnnotatedField<T> getAnnotated()
+ {
+ return delegate.getAnnotated();
+ }
+
+ @Override
+ public AnnotatedFieldConfigurator<T> removeAll()
+ {
+ actions.add("--");
+ delegate.removeAll();
+ return this;
+ }
+
+ @Override
+ public AnnotatedFieldConfigurator<T> remove(final Predicate<Annotation> predicate)
+ {
+ delegate.remove(a ->
+ {
+ if (predicate.test(a))
+ {
+ actions.add("-@" + a);
+ return true;
+ }
+ return false;
+ });
+ return this;
+ }
+
+ @Override
+ public AnnotatedFieldConfigurator<T> add(final Annotation annotation)
+ {
+ actions.add("+@" + annotation.annotationType());
+ delegate.add(annotation);
+ return this;
+ }
+ }
+
+ public static class TrackingAnnotatedMethodConfiguratorImpl<T> implements AnnotatedMethodConfigurator<T>
+ {
+ private final AnnotatedMethodConfigurator<T> delegate;
+ private final List<String> actions;
+
+ public TrackingAnnotatedMethodConfiguratorImpl(final AnnotatedMethodConfigurator<T> delegate,
+ final List<String> actions)
+ {
+ this.delegate = delegate;
+ this.actions = actions;
+ this.actions.add("\n\t");
+ }
+
+ @Override
+ public final boolean equals(final Object o)
+ {
+ if (!(o instanceof TrackingAnnotatedMethodConfiguratorImpl))
+ {
+ return false;
+ }
+
+ final TrackingAnnotatedMethodConfiguratorImpl<?> that = (TrackingAnnotatedMethodConfiguratorImpl<?>) o;
+ return delegate.equals(that.delegate);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return delegate.hashCode();
+ }
+
+ @Override
+ public String toString()
+ {
+ return "TrackingMethod(" + delegate + ")";
+ }
+
+ @Override
+ public AnnotatedMethodConfigurator<T> add(final Annotation annotation)
+ {
+ actions.add("+@" + annotation.annotationType());
+ delegate.add(annotation);
+ return this;
+ }
+
+ @Override
+ public Stream<AnnotatedParameterConfigurator<T>> filterParams(final Predicate<AnnotatedParameter<T>> predicate)
+ {
+ return delegate.filterParams(a ->
+ {
+ if (predicate.test(a))
+ {
+ actions.add("-p@" + a);
+ return true;
+ }
+ return false;
+ });
+ }
+
+ @Override
+ public AnnotatedMethod<T> getAnnotated()
+ {
+ return delegate.getAnnotated();
+ }
+
+ @Override
+ public List<AnnotatedParameterConfigurator<T>> params()
+ {
+ return delegate.params().stream()
+ .map(p -> new TrackingAnnotatedParameterConfiguratorImpl(p, actions))
+ .map(p -> (AnnotatedParameterConfigurator<T>) p)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public AnnotatedMethodConfigurator<T> remove(final Predicate<Annotation> predicate)
+ {
+ delegate.remove(a ->
+ {
+ if (predicate.test(a))
+ {
+ actions.add("-@" + a.toString());
+ return true;
+ }
+ return false;
+ });
+ return this;
+ }
+
+ @Override
+ public AnnotatedMethodConfigurator<T> removeAll()
+ {
+ actions.add("--");
+ delegate.removeAll();
+ return this;
+ }
+ }
+
+ public static class TrackingAnnotatedConstructorConfiguratorImpl<T> implements AnnotatedConstructorConfigurator<T>
+ {
+ private final AnnotatedConstructorConfigurator<T> delegate;
+ private final List<String> actions;
+
+ public TrackingAnnotatedConstructorConfiguratorImpl(final AnnotatedConstructorConfigurator<T> delegate,
+ final List<String> actions)
+ {
+ this.delegate = delegate;
+ this.actions = actions;
+ this.actions.add("\n\t");
+ }
+
+ @Override
+ public final boolean equals(final Object o)
+ {
+ if (!(o instanceof TrackingAnnotatedConstructorConfiguratorImpl))
+ {
+ return false;
+ }
+
+ final TrackingAnnotatedConstructorConfiguratorImpl<?> that =
+ (TrackingAnnotatedConstructorConfiguratorImpl<?>) o;
+ return delegate.equals(that.delegate);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return delegate.hashCode();
+ }
+
+ @Override
+ public String toString()
+ {
+ return "TrackingConstructor(" + delegate + ")";
+ }
+
+ @Override
+ public AnnotatedConstructor<T> getAnnotated()
+ {
+ return delegate.getAnnotated();
+ }
+
+ @Override
+ public AnnotatedConstructorConfigurator<T> add(final Annotation annotation)
+ {
+ actions.add("+@" + annotation.annotationType());
+ delegate.add(annotation);
+ return this;
+ }
+
+ @Override
+ public AnnotatedConstructorConfigurator<T> remove(final Predicate<Annotation> predicate)
+ {
+ actions.add("-@" + predicate.toString());
+ delegate.remove(predicate);
+ return this;
+ }
+
+ @Override
+ public AnnotatedConstructorConfigurator<T> removeAll()
+ {
+ actions.add("--");
+ delegate.removeAll();
+ return this;
+ }
+
+ @Override
+ public List<AnnotatedParameterConfigurator<T>> params()
+ {
+ return delegate.params().stream()
+ .map(p -> new TrackingAnnotatedParameterConfiguratorImpl(p, actions))
+ .map(p -> (AnnotatedParameterConfigurator<T>) p)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public Stream<AnnotatedParameterConfigurator<T>> filterParams(final Predicate<AnnotatedParameter<T>> predicate)
+ {
+ return delegate.filterParams(a ->
+ {
+ if (predicate.test(a))
+ {
+ actions.add("-p@" + a.toString());
+ return true;
+ }
+ return false;
+ });
+ }
+ }
+
+ public static class TrackingAnnotatedParameterConfiguratorImpl<T> implements AnnotatedParameterConfigurator<T>
+ {
+ private final AnnotatedParameterConfigurator<T> delegate;
+ private final List<String> actions;
+
+ public TrackingAnnotatedParameterConfiguratorImpl(final AnnotatedParameterConfigurator<T> delegate,
+ final List<String> actions)
+ {
+ this.delegate = delegate;
+ this.actions = actions;
+ this.actions.add("\n\t");
+ }
+
+ @Override
+ public final boolean equals(final Object o)
+ {
+ if (!(o instanceof TrackingAnnotatedParameterConfiguratorImpl))
+ {
+ return false;
+ }
+
+ final TrackingAnnotatedParameterConfiguratorImpl<?> that =
+ (TrackingAnnotatedParameterConfiguratorImpl<?>) o;
+ return delegate.equals(that.delegate);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return delegate.hashCode();
+ }
+
+ @Override
+ public String toString()
+ {
+ return "TrackingParameter(" + delegate + ")";
+ }
+
+ @Override
+ public AnnotatedParameterConfigurator<T> add(final Annotation annotation)
+ {
+ actions.add("+@" + annotation.annotationType());
+ delegate.add(annotation);
+ return this;
+ }
+
+ @Override
+ public AnnotatedParameter<T> getAnnotated()
+ {
+ return delegate.getAnnotated();
+ }
+
+ @Override
+ public AnnotatedParameterConfigurator<T> remove(final Predicate<Annotation> predicate)
+ {
+ delegate.remove(a ->
+ {
+ if (predicate.test(a))
+ {
+ actions.add("-p@" + a.toString());
+ return true;
+ }
+ return false;
+ });
+ return this;
+ }
+
+ @Override
+ public AnnotatedParameterConfigurator<T> removeAll()
+ {
+ actions.add("--");
+ delegate.removeAll();
+ return this;
+ }
+ }
+}
\ No newline at end of file
diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/container/InterceptionFactoryImpl.java b/webbeans-impl/src/main/java/org/apache/webbeans/container/InterceptionFactoryImpl.java
index 3064902d3..0262f925f 100644
--- a/webbeans-impl/src/main/java/org/apache/webbeans/container/InterceptionFactoryImpl.java
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/container/InterceptionFactoryImpl.java
@@ -20,28 +20,30 @@ package org.apache.webbeans.container;
import org.apache.webbeans.config.WebBeansContext;
import org.apache.webbeans.configurator.AnnotatedTypeConfiguratorImpl;
+import org.apache.webbeans.configurator.TrackingAnnotatedTypeConfiguratorImpl;
import org.apache.webbeans.context.creational.CreationalContextImpl;
import org.apache.webbeans.intercept.InterceptorResolutionService;
-import org.apache.webbeans.portable.AnnotatedTypeImpl;
import org.apache.webbeans.proxy.InterceptorDecoratorProxyFactory;
import org.apache.webbeans.util.WebBeansUtil;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.InterceptionFactory;
-import javax.enterprise.inject.spi.Interceptor;
import javax.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator;
import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Supplier;
+
+import static java.util.Optional.ofNullable;
public class InterceptionFactoryImpl<T> implements InterceptionFactory<T> /*todo: make it serializable*/
{
private final CreationalContextImpl<T> creationalContext;
- private final AnnotatedTypeConfiguratorImpl<T> configurator;
private final Set<Annotation> qualifiers;
private final WebBeansContext context;
+ private final AnnotatedType<T> at;
+ private TrackingAnnotatedTypeConfiguratorImpl<T> configurator;
private boolean ignoreFinals;
private volatile boolean called;
@@ -49,9 +51,10 @@ public class InterceptionFactoryImpl<T> implements InterceptionFactory<T> /*todo
Set<Annotation> qualifiers, CreationalContextImpl<T> cc)
{
this.context = context;
- this.configurator = new AnnotatedTypeConfiguratorImpl<>(context, at);
+ this.configurator = null; // computed later
this.qualifiers = qualifiers;
this.creationalContext = cc;
+ this.at = at;
}
@Override
@@ -64,6 +67,12 @@ public class InterceptionFactoryImpl<T> implements InterceptionFactory<T> /*todo
@Override
public AnnotatedTypeConfigurator<T> configure()
{
+ if (configurator == null)
+ {
+ // configurator = new AnnotatedTypeConfiguratorImpl<>(context, at);
+ AnnotatedTypeConfiguratorImpl<T> realConfig = new AnnotatedTypeConfiguratorImpl<>(context, at);
+ configurator = new TrackingAnnotatedTypeConfiguratorImpl<>(realConfig);
+ }
return configurator;
}
@@ -72,31 +81,42 @@ public class InterceptionFactoryImpl<T> implements InterceptionFactory<T> /*todo
{
check();
- ClassLoader classLoader = originalInstance.getClass().getClassLoader();
- if (classLoader == null)
- {
- classLoader = WebBeansUtil.getCurrentClassLoader();
- }
-
- InterceptorDecoratorProxyFactory factory = context.getInterceptorDecoratorProxyFactory();
- AnnotatedTypeImpl<T> newAnnotatedType = configurator.getNewAnnotatedType();
- InterceptorResolutionService.BeanInterceptorInfo interceptorInfo =
- context.getInterceptorResolutionService()
- .calculateInterceptorInfo(newAnnotatedType.getTypeClosure(), qualifiers, newAnnotatedType, !ignoreFinals);
- Class<T> subClass = factory.createProxyClass(interceptorInfo, newAnnotatedType, classLoader);
+ final ClassLoader classLoader = ofNullable(originalInstance.getClass().getClassLoader())
+ .orElseGet(WebBeansUtil::getCurrentClassLoader);
- Map<Interceptor<?>,Object> interceptorInstances = context.getInterceptorResolutionService()
- .createInterceptorInstances(interceptorInfo, creationalContext);
+ AnnotatedType<T> newAnnotatedType = configurator == null ? at : configurator.getNewAnnotatedType();
+ newAnnotatedType.getTypeClosure(); // make sure the toString bellow is accurate
+ String passivationId = InterceptionFactory.class.getName() + ">>" + newAnnotatedType + "<<" + ignoreFinals;
- Map<Method, List<Interceptor<?>>> methodInterceptors =
- context.getInterceptorResolutionService().createMethodInterceptors(interceptorInfo);
+ // if configure() has not been called, we need to create a new configurator with the muted annotated type
+ if (configurator != null) // meaning app changed dynamically the annotated type configuration
+ {
+ passivationId = passivationId + ">>" + configurator.getPassivationId();
+ }
- // this is a good question actually, should we even support it?
- String passivationId = InterceptionFactory.class.getName() + ">>" + newAnnotatedType.toString();
+ InterceptorResolutionService interceptorResolutionService = context.getInterceptorResolutionService();
+ InterceptionFactoryCacheEntry cache = context
+ .getWebBeansUtil()
+ .getInterceptionFactoryCache()
+ .computeIfAbsent(passivationId, () -> {
+ InterceptorResolutionService.BeanInterceptorInfo interceptorInfo =
+ interceptorResolutionService
+ .calculateInterceptorInfo(newAnnotatedType.getTypeClosure(), qualifiers, newAnnotatedType, !ignoreFinals);
+ InterceptorDecoratorProxyFactory factory = context.getInterceptorDecoratorProxyFactory();
+ return new InterceptionFactoryCacheEntry(
+ factory.createProxyClass(interceptorInfo, newAnnotatedType, classLoader),
+ interceptorInfo);
+ });
- return context.getInterceptorResolutionService().createProxiedInstance(
- originalInstance, creationalContext, creationalContext, interceptorInfo, subClass,
- methodInterceptors, passivationId, interceptorInstances, c -> false, (a, d) -> d);
+ Map<javax.enterprise.inject.spi.Interceptor<?>, Object> interceptorInstances = interceptorResolutionService
+ .createInterceptorInstances(cache.interceptorInfo, creationalContext);
+ Map<java.lang.reflect.Method, java.util.List<javax.enterprise.inject.spi.Interceptor<?>>> methodInterceptors =
+ interceptorResolutionService.createMethodInterceptors(cache.interceptorInfo);
+ return interceptorResolutionService.createProxiedInstance(
+ originalInstance, creationalContext, creationalContext, cache.interceptorInfo,
+ (Class<? extends T>) cache.proxyClass,
+ methodInterceptors, passivationId, interceptorInstances,
+ c -> false, (a, d) -> d);
}
private void check()
@@ -118,4 +138,50 @@ public class InterceptionFactoryImpl<T> implements InterceptionFactory<T> /*todo
throw new IllegalStateException("createInterceptedInstance() can be called only once");
}
}
+
+ public static class InterceptionFactoryCache
+ {
+ private final Map<String, InterceptionFactoryCacheEntry> cache = new ConcurrentHashMap<>();
+
+ private InterceptionFactoryCacheEntry computeIfAbsent(
+ final String interceptionFactoryCacheKey, final Supplier<InterceptionFactoryCacheEntry> compute)
+ {
+ InterceptionFactoryCacheEntry entry = cache.get(interceptionFactoryCacheKey);
+ if (entry == null)
+ {
+ // we do not want to create twice a proxy class,
+ // "bottleneck" but quickly cached
+ // so "ok"ish
+ synchronized (this)
+ {
+ entry = cache.get(interceptionFactoryCacheKey);
+ if (entry == null)
+ {
+ entry = compute.get();
+ cache.putIfAbsent(interceptionFactoryCacheKey, entry);
+ }
+ }
+ }
+ return entry;
+ }
+
+ public int size()
+ {
+ return cache.size();
+ }
+ }
+
+ private static class InterceptionFactoryCacheEntry
+ {
+ private final Class<?> proxyClass;
+ private final InterceptorResolutionService.BeanInterceptorInfo interceptorInfo;
+
+ private InterceptionFactoryCacheEntry(
+ final Class<?> proxyClass,
+ final InterceptorResolutionService.BeanInterceptorInfo interceptorInfo)
+ {
+ this.proxyClass = proxyClass;
+ this.interceptorInfo = interceptorInfo;
+ }
+ }
}
diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/portable/AnnotatedTypeImpl.java b/webbeans-impl/src/main/java/org/apache/webbeans/portable/AnnotatedTypeImpl.java
index 1610b745b..e26ec7fec 100644
--- a/webbeans-impl/src/main/java/org/apache/webbeans/portable/AnnotatedTypeImpl.java
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/portable/AnnotatedTypeImpl.java
@@ -209,7 +209,7 @@ public class AnnotatedTypeImpl<X>
@Override
public int hashCode() // enough, no need to create a hashcode from attributes
{
- return super.hashCode();
+ return getJavaClass().hashCode();
}
private State getState()
diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/util/WebBeansUtil.java b/webbeans-impl/src/main/java/org/apache/webbeans/util/WebBeansUtil.java
index cbd36388a..b30ed3ed5 100644
--- a/webbeans-impl/src/main/java/org/apache/webbeans/util/WebBeansUtil.java
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/util/WebBeansUtil.java
@@ -55,6 +55,7 @@ import org.apache.webbeans.config.OwbWildcardTypeImpl;
import org.apache.webbeans.config.WebBeansContext;
import org.apache.webbeans.container.AnnotatedTypeWrapper;
import org.apache.webbeans.container.InjectionResolver;
+import org.apache.webbeans.container.InterceptionFactoryImpl;
import org.apache.webbeans.context.control.ActivateRequestContextInterceptorBean;
import org.apache.webbeans.context.control.RequestContextControllerBean;
import org.apache.webbeans.exception.WebBeansConfigurationException;
@@ -173,6 +174,8 @@ public final class WebBeansUtil
private final ConcurrentMap<EventCacheKey, Boolean> validEventType = new ConcurrentHashMap<>();
private final ConcurrentMap<Type, Boolean> notContainerEvents = new ConcurrentHashMap<>();
+ private final InterceptionFactoryImpl.InterceptionFactoryCache interceptionFactoryCache = new InterceptionFactoryImpl.InterceptionFactoryCache();
+
private InstanceBean instanceBean;
private EventBean eventBean;
@@ -1762,6 +1765,11 @@ public final class WebBeansUtil
}
}
+ public InterceptionFactoryImpl.InterceptionFactoryCache getInterceptionFactoryCache()
+ {
+ return interceptionFactoryCache;
+ }
+
public InterceptionFactoryBean getInterceptionFactoryBean()
{
return new InterceptionFactoryBean(webBeansContext);
diff --git a/webbeans-impl/src/test/java/org/apache/webbeans/configurator/TrackingAnnotatedTypeConfiguratorImplTest.java b/webbeans-impl/src/test/java/org/apache/webbeans/configurator/TrackingAnnotatedTypeConfiguratorImplTest.java
new file mode 100644
index 000000000..23281de3f
--- /dev/null
+++ b/webbeans-impl/src/test/java/org/apache/webbeans/configurator/TrackingAnnotatedTypeConfiguratorImplTest.java
@@ -0,0 +1,251 @@
+/*
+ * 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.webbeans.configurator;
+
+import org.apache.webbeans.config.WebBeansContext;
+import org.apache.webbeans.test.AbstractUnitTest;
+import org.junit.Test;
+
+import javax.enterprise.inject.spi.AnnotatedConstructor;
+import javax.enterprise.inject.spi.AnnotatedField;
+import javax.enterprise.inject.spi.AnnotatedMethod;
+import javax.enterprise.inject.spi.AnnotatedParameter;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.configurator.AnnotatedConstructorConfigurator;
+import javax.enterprise.inject.spi.configurator.AnnotatedFieldConfigurator;
+import javax.enterprise.inject.spi.configurator.AnnotatedMethodConfigurator;
+import javax.enterprise.inject.spi.configurator.AnnotatedParameterConfigurator;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static org.junit.Assert.assertTrue;
+
+
+public class TrackingAnnotatedTypeConfiguratorImplTest extends AbstractUnitTest {
+
+ @Test
+ public void shouldTrackAllConfiguratorActions() {
+ AnnotatedTypeConfiguratorImpl<MyBean> base = new FullStubTypeConfigurator<>();
+
+ TrackingAnnotatedTypeConfiguratorImpl<MyBean> tracking = new TrackingAnnotatedTypeConfiguratorImpl<>(base);
+
+ tracking.add(getDummyAnn());
+ tracking.remove(a -> a.annotationType().equals(DummyAnn.class));
+ tracking.removeAll();
+
+ tracking.fields().forEach(f -> {
+ f.add(getDummyAnn());
+ f.remove(a -> a.annotationType().equals(DummyAnn.class));
+ f.removeAll();
+ });
+
+ tracking.methods().forEach(m -> {
+ m.add(getDummyAnn());
+ m.remove(a -> a.annotationType().equals(DummyAnn.class));
+ m.removeAll();
+
+ m.params().forEach(p -> {
+ p.add(getDummyAnn());
+ p.remove(a -> a.annotationType().equals(DummyAnn.class));
+ p.removeAll();
+ });
+ });
+
+ tracking.constructors().forEach(c -> {
+ c.add(getDummyAnn());
+ c.remove(a -> a.annotationType().equals(DummyAnn.class));
+ c.removeAll();
+
+ c.params().forEach(p -> {
+ p.add(getDummyAnn());
+ p.remove(a -> a.annotationType().equals(DummyAnn.class));
+ p.removeAll();
+ });
+ });
+
+ tracking.filterFields(f -> true).collect(Collectors.toList());
+ tracking.filterMethods(m -> true).collect(Collectors.toList());
+ tracking.filterConstructors(c -> true).collect(Collectors.toList());
+
+ final String passivationId = tracking.getPassivationId();
+
+ assertTrue(passivationId.contains("+@interface " + DummyAnn.class.getName()));
+ assertTrue(passivationId.contains("--")); // at least one removeAll()
+ assertTrue(passivationId.contains("-@")); // from any predicate matched removal
+ assertTrue(passivationId.contains("-f@")); // filterFields
+ assertTrue(passivationId.contains("-m@")); // filterMethods
+ assertTrue(passivationId.contains("-c@")); // filterConstructors
+ assertTrue(passivationId.contains("-p@")); // param filter
+ }
+
+ public static Annotation getDummyAnn() {
+ return WithDummyAnn.class.getAnnotation(DummyAnn.class);
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface DummyAnn {}
+
+ @DummyAnn
+ static class WithDummyAnn {}
+
+ public static class MyBean {
+ @DummyAnn
+ public String field;
+
+ @DummyAnn
+ public void method(@DummyAnn String param) {}
+
+ @DummyAnn
+ public MyBean() {}
+ }
+
+ public static class FullStubTypeConfigurator<T> extends AnnotatedTypeConfiguratorImpl<MyBean> {
+ public FullStubTypeConfigurator() {
+ super(WebBeansContext.currentInstance(),
+ WebBeansContext.currentInstance()
+ .getBeanManagerImpl()
+ .createAnnotatedType(MyBean.class));
+ }
+
+ @Override
+ public Set<AnnotatedFieldConfigurator<? super MyBean>> fields() {
+ Set<AnnotatedFieldConfigurator<? super MyBean>> annotatedFieldConfigurators = new HashSet<>();
+ annotatedFieldConfigurators.add(new FullStubFieldConfigurator<>());
+ return annotatedFieldConfigurators;
+ }
+
+ @Override
+ public Set<AnnotatedMethodConfigurator<? super MyBean>> methods() {
+ Set<AnnotatedMethodConfigurator<? super MyBean>> annotatedMethodConfigurators = new HashSet<>();
+ annotatedMethodConfigurators.add(new FullStubMethodConfigurator<>());
+ return annotatedMethodConfigurators;
+ }
+
+ @Override
+ public Set<AnnotatedConstructorConfigurator<MyBean>> constructors() {
+ Set<AnnotatedConstructorConfigurator<MyBean>> annotatedConstructorConfigurators = new HashSet<>();
+ annotatedConstructorConfigurators.add(new FullStubConstructorConfigurator<>());
+ return annotatedConstructorConfigurators;
+ }
+
+ @Override
+ public Stream<AnnotatedFieldConfigurator<? super MyBean>> filterFields(Predicate<AnnotatedField<?
+ super MyBean>> p) {
+ p.test(null);
+ return fields().stream();
+ }
+
+ @Override
+ public Stream<AnnotatedMethodConfigurator<? super MyBean>> filterMethods(Predicate<AnnotatedMethod<?
+ super MyBean>> p) {
+ p.test(null);
+ return methods().stream();
+ }
+
+ @Override
+ public Stream<AnnotatedConstructorConfigurator<MyBean>> filterConstructors(Predicate<AnnotatedConstructor<MyBean>> p) {
+ p.test(null);
+ return constructors().stream();
+ }
+
+ @Override
+ public AnnotatedType<MyBean> getAnnotated() {
+ return super.getAnnotated();
+ }
+ }
+
+ public static class FullStubFieldConfigurator<T> implements AnnotatedFieldConfigurator<MyBean> {
+ @Override public AnnotatedField<MyBean> getAnnotated() {return null;}
+
+ @Override public AnnotatedFieldConfigurator<MyBean> removeAll() {return this;}
+
+ @Override public AnnotatedFieldConfigurator<MyBean> remove(Predicate<Annotation> predicate) {
+ predicate.test(getDummyAnn()); return this;
+ }
+
+ @Override public AnnotatedFieldConfigurator<MyBean> add(Annotation annotation) {return this;}
+ }
+
+ public static class FullStubMethodConfigurator<T> implements AnnotatedMethodConfigurator<MyBean> {
+ @Override public AnnotatedMethodConfigurator<MyBean> add(Annotation annotation) {return this;}
+
+ @Override
+ public Stream<AnnotatedParameterConfigurator<MyBean>> filterParams(Predicate<AnnotatedParameter<MyBean>> p) {
+ p.test(null); return params().stream();
+ }
+
+ @Override public AnnotatedMethod<MyBean> getAnnotated() {return null;}
+
+ @Override public List<AnnotatedParameterConfigurator<MyBean>> params() {
+ List<AnnotatedParameterConfigurator<MyBean>> annotatedParameterConfigurators = new ArrayList<>();
+ annotatedParameterConfigurators.add(new FullStubParamConfigurator<>());
+ return annotatedParameterConfigurators;
+ }
+
+ @Override public AnnotatedMethodConfigurator<MyBean> remove(Predicate<Annotation> predicate) {
+ predicate.test(getDummyAnn()); return this;
+ }
+
+ @Override public AnnotatedMethodConfigurator<MyBean> removeAll() {return this;}
+ }
+
+ public static class FullStubConstructorConfigurator<T> implements AnnotatedConstructorConfigurator<MyBean> {
+ @Override public AnnotatedConstructor<MyBean> getAnnotated() {return null;}
+
+ @Override public AnnotatedConstructorConfigurator<MyBean> add(Annotation annotation) {return this;}
+
+ @Override
+ public AnnotatedConstructorConfigurator<MyBean> remove(Predicate<Annotation> predicate) {
+ predicate.test(getDummyAnn()); return this;
+ }
+
+ @Override public AnnotatedConstructorConfigurator<MyBean> removeAll() {return this;}
+
+ @Override public List<AnnotatedParameterConfigurator<MyBean>> params() {
+ List<AnnotatedParameterConfigurator<MyBean>> annotatedParameterConfigurators = new ArrayList<>();
+ annotatedParameterConfigurators.add(new FullStubParamConfigurator<>());
+ return annotatedParameterConfigurators;
+ }
+
+ @Override
+ public Stream<AnnotatedParameterConfigurator<MyBean>> filterParams(Predicate<AnnotatedParameter<MyBean>> p) {
+ p.test(null); return params().stream();
+ }
+ }
+
+ public static class FullStubParamConfigurator<T> implements AnnotatedParameterConfigurator<MyBean> {
+ @Override public AnnotatedParameterConfigurator<MyBean> add(Annotation annotation) {return this;}
+
+ @Override public AnnotatedParameter<MyBean> getAnnotated() {return null;}
+
+ @Override public AnnotatedParameterConfigurator<MyBean> remove(Predicate<Annotation> predicate) {
+ predicate.test(getDummyAnn()); return this;
+ }
+
+ @Override public AnnotatedParameterConfigurator<MyBean> removeAll() {return this;}
+ }
+}
\ No newline at end of file
diff --git a/webbeans-impl/src/test/java/org/apache/webbeans/test/interceptors/factory/InterceptorDecoratorProxyFactoryTest.java b/webbeans-impl/src/test/java/org/apache/webbeans/test/interceptors/factory/InterceptorDecoratorProxyFactoryTest.java
index 887342b62..b5737e58c 100644
--- a/webbeans-impl/src/test/java/org/apache/webbeans/test/interceptors/factory/InterceptorDecoratorProxyFactoryTest.java
+++ b/webbeans-impl/src/test/java/org/apache/webbeans/test/interceptors/factory/InterceptorDecoratorProxyFactoryTest.java
@@ -32,25 +32,52 @@ import java.util.Iterator;
import java.util.List;
import java.util.Set;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.Produces;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.InjectionPoint;
+import javax.enterprise.inject.spi.InterceptionFactory;
+import javax.enterprise.util.AnnotationLiteral;
+import javax.inject.Qualifier;
+import org.apache.webbeans.annotation.EmptyAnnotationLiteral;
import org.apache.webbeans.config.WebBeansContext;
import org.apache.webbeans.exception.WebBeansException;
-import org.apache.webbeans.test.AbstractUnitTest;
-import org.apache.webbeans.test.component.intercept.webbeans.TransactionalInterceptor;
-import org.apache.webbeans.test.interceptors.factory.beans.ClassInterceptedClass;
import org.apache.webbeans.proxy.InterceptorDecoratorProxyFactory;
-
import org.apache.webbeans.proxy.InterceptorHandler;
import org.apache.webbeans.proxy.OwbInterceptorProxy;
+import org.apache.webbeans.test.AbstractUnitTest;
+import org.apache.webbeans.test.component.intercept.webbeans.TransactionalInterceptor;
+import org.apache.webbeans.test.interceptors.factory.beans.ClassInterceptedClass;
import org.apache.webbeans.test.interceptors.factory.beans.TonsOfMethodsInterceptedClass;
-import org.apache.webbeans.util.ClassUtil;
import org.apache.webbeans.test.util.CustomBaseType;
import org.apache.webbeans.test.util.CustomType;
import org.apache.webbeans.test.util.ExtendedSpecificClass;
import org.apache.webbeans.test.util.GenericInterface;
import org.apache.webbeans.test.util.SpecificClass;
+import org.apache.webbeans.util.ClassUtil;
import org.junit.Assert;
import org.junit.Test;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+
/**
* Test the {@link org.apache.webbeans.proxy.InterceptorDecoratorProxyFactory}
@@ -58,6 +85,35 @@ import org.junit.Test;
public class InterceptorDecoratorProxyFactoryTest extends AbstractUnitTest
{
+ @ApplicationScoped
+ public static class IFProducer {
+ @Produces
+ public Runnable wrap1(final InterceptionFactory<Runnable> interceptionFactory) {
+ return interceptionFactory.createInterceptedInstance(() -> {});
+ }
+
+ @Produces
+ @SimpleQualifier
+ public Runnable wrap2(final InterceptionFactory<Runnable> interceptionFactory) {
+ interceptionFactory.configure().add(new EmptyAnnotationLiteral<SimpleQualifier>(){});
+ return interceptionFactory.createInterceptedInstance(() -> {});
+ }
+ }
+
+ @Test
+ public void testEnsureOneProxyPerAT() {
+ startContainer(IFProducer.class);
+ final AnnotationLiteral<SimpleQualifier> simpleQualifier = new EmptyAnnotationLiteral<SimpleQualifier>(){};
+ final Runnable r11 = getInstance(Runnable.class);
+ final Runnable r12 = getInstance(Runnable.class);
+ assertEquals(1, getWebBeansContext().getWebBeansUtil().getInterceptionFactoryCache().size());
+ final Runnable r2 = getInstance(Runnable.class, simpleQualifier);
+ assertEquals(2, getWebBeansContext().getWebBeansUtil().getInterceptionFactoryCache().size());
+ assertSame(r11.getClass(), r12.getClass());
+ assertNotSame(r2.getClass(), r11.getClass());
+ assertSame(getInstance(Runnable.class, simpleQualifier).getClass(), r2.getClass());
+ }
+
@Test
public void testSimpleProxyCreation() throws Exception
{
@@ -252,4 +308,12 @@ public class InterceptorDecoratorProxyFactoryTest extends AbstractUnitTest
}
}
}
+
+ @Target({ METHOD })
+ @Retention(RUNTIME)
+ @Documented
+ @Qualifier
+ public @interface SimpleQualifier
+ {
+ }
}