Skip to content

Commit

Permalink
Add Bean support
Browse files Browse the repository at this point in the history
Signed-off-by: Dmitry Aleksandrov <dmitry.aleksandrov@oracle.com>
  • Loading branch information
dalexandrov committed Nov 13, 2023
1 parent a7f196d commit 836e6bf
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 52 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
*
* Licensed 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 io.helidon.microprofile.testing.common;

import jakarta.enterprise.context.ApplicationScoped;

import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Add a bean.
* This is intended for test sources where we do not want to add {@code beans.xml} as this would add
* all test classes as beans.
* The bean will be added by default with {@link ApplicationScoped}.
* The class will be instantiated using CDI and will be available for injection into test classes and other beans.
* This annotation can be repeated.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Repeatable(CommonAddBeans.class)
public @interface CommonAddBean {
/**
* Class of the bean.
* @return the class of a bean
*/
Class<?> value();

/**
* Scope of the bean.
* Only {@link jakarta.inject.Singleton}, {@link ApplicationScoped}
* and {@link jakarta.enterprise.context.RequestScoped} scopes are supported.
*
* @return scope of the bean
*/
Class<? extends Annotation> scope() default ApplicationScoped.class;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
*
* Licensed 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 io.helidon.microprofile.testing.common;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* A repeatable container for {@link CommonAddBean}.
* No need to use this annotation, just repeat {@link CommonAddBean} annotation
* on test class.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface CommonAddBeans {
/**
* Beans to be added.
* @return add bean annotations
*/
CommonAddBean[] value();
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package io.helidon.microprofile.testing.common;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
Expand All @@ -28,9 +29,10 @@
* Common CDI Extension.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Repeatable(CdiExtensions.class)
public @interface CdiExtension {
@Target({ElementType.TYPE})
@Repeatable(CommonCdiExtensions.class)
@Inherited
public @interface CommonCdiExtension {

/**
* CDI Extension.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package io.helidon.microprofile.testing.common;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
Expand All @@ -25,13 +26,14 @@
* Common CDI Extensions for testing.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface CdiExtensions {
@Target({ElementType.TYPE})
@Inherited
public @interface CommonCdiExtensions {

/**
* Return CDI Extension.
*
* @return CDIExtension[]
*/
CdiExtension[] value();
CommonCdiExtension[] value();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
*
* Licensed 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.
*/

/**
* Common Testing Extensions.
*/
package io.helidon.microprofile.testing.common;
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,29 @@

package io.helidon.microprofile.testing.jaxrs;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import io.helidon.microprofile.server.JaxRsCdiExtension;
import io.helidon.microprofile.server.ServerCdiExtension;
import io.helidon.microprofile.testing.common.CdiExtension;
import io.helidon.microprofile.testing.common.CommonAddBean;
import io.helidon.microprofile.testing.common.CommonCdiExtension;

import org.glassfish.jersey.ext.cdi1x.internal.CdiComponentProvider;

/**
* JAX_RS Testing annotation.
*/
@CdiExtension(ServerCdiExtension.class)
@CdiExtension(JaxRsCdiExtension.class)
@CdiExtension(CdiComponentProvider.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Inherited
@CommonCdiExtension(ServerCdiExtension.class)
@CommonCdiExtension(JaxRsCdiExtension.class)
@CommonCdiExtension(CdiComponentProvider.class)
@CommonCdiExtension(org.glassfish.jersey.ext.cdi1x.internal.ProcessAllAnnotatedTypes.class)
@CommonAddBean(org.glassfish.jersey.weld.se.WeldRequestScope.class)
public @interface AddJaxRs {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
*
* Licensed 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.
*/

/**
* JAX-RS Extension for Testing.
*/
package io.helidon.microprofile.testing.jaxrs;
1 change: 1 addition & 0 deletions microprofile/testing/jaxrs/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

requires transitive jakarta.cdi;
requires transitive jakarta.ws.rs;
requires jersey.weld2.se;

exports io.helidon.microprofile.testing.jaxrs;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package io.helidon.microprofile.testing.junit5;

import java.io.Serial;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Array;
Expand All @@ -31,10 +30,14 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import io.helidon.config.mp.MpConfigSources;
import io.helidon.config.yaml.mp.YamlMpConfigSource;
import io.helidon.microprofile.testing.common.CdiExtension;
import io.helidon.microprofile.testing.common.CommonAddBean;
import io.helidon.microprofile.testing.common.CommonAddBeans;
import io.helidon.microprofile.testing.common.CommonCdiExtension;
import io.helidon.microprofile.testing.common.CommonCdiExtensions;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.context.Dependent;
Expand All @@ -49,7 +52,6 @@
import jakarta.enterprise.inject.spi.InjectionPoint;
import jakarta.enterprise.inject.spi.ProcessInjectionPoint;
import jakarta.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator;
import jakarta.enterprise.util.AnnotationLiteral;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import jakarta.ws.rs.client.Client;
Expand Down Expand Up @@ -140,13 +142,6 @@ public void beforeAll(ExtensionContext context) {
}
validatePerClass();

// add beans when using JaxRS
// AddJaxRs addJaxRsAnnotation = testClass.getAnnotation(AddJaxRs.class);
// if (addJaxRsAnnotation != null){
// classLevelExtensions.add(AddProcessAnnotatedTypesLiteral.INSTANCE);
// classLevelBeans.add(AddWeldRequestScopeLiteral.INSTANCE);
// }

configure(classLevelConfigMeta);

if (!classLevelConfigMeta.useExisting) {
Expand All @@ -158,14 +153,33 @@ public void beforeAll(ExtensionContext context) {
}

@SuppressWarnings("unchecked")
private Class<? extends Extension>[] getFeatureExtensions(Class<?> testClass) {
private List<Class<? extends Extension>> getFeatureExtensions(Class<?> testClass) {
return Arrays.stream(testClass.getDeclaredAnnotations())
.flatMap(a -> Arrays.stream(a.getClass().getDeclaredAnnotations()))
.filter(a -> a.annotationType() == CdiExtension.class)
.map(CdiExtension.class::cast)
.map(CdiExtension::value)
.toList()
.toArray(new Class[0]);
.flatMap(a -> Arrays.stream(a.annotationType().getDeclaredAnnotations()))
.filter(a -> a instanceof CommonCdiExtensions)
.map(CommonCdiExtensions.class::cast)
.flatMap(e -> Arrays.stream(e.value()))
.map(CommonCdiExtension::value)
.collect(Collectors.toList());
}

private List<Class<?>> getFeatureBeans(Class<?> testClass) {

ArrayList<Class<?>> result = new ArrayList<>(Arrays.stream(testClass.getDeclaredAnnotations())
.flatMap(a -> Arrays.stream(a.annotationType().getDeclaredAnnotations()))
.filter(a -> a instanceof CommonAddBean)
.map(CommonAddBean.class::cast)
.map(CommonAddBean::value)
.collect(Collectors.toList()));

result.addAll(Arrays.stream(testClass.getDeclaredAnnotations())
.flatMap(a -> Arrays.stream(a.annotationType().getDeclaredAnnotations()))
.filter(a -> a instanceof CommonAddBeans)
.map(CommonAddBeans.class::cast)
.flatMap(e -> Arrays.stream(e.value()))
.map(CommonAddBean::value)
.collect(Collectors.toList()));
return result;
}

private <T extends Annotation> T[] getAnnotations(Class<?> testClass, Class<T> annotClass) {
Expand Down Expand Up @@ -254,29 +268,6 @@ private void validatePerClass() {
}
}
}

// AddJaxRs addJaxRsAnnotation = testClass.getAnnotation(AddJaxRs.class);
// if (addJaxRsAnnotation != null){
// if (testClass.getAnnotation(DisableDiscovery.class) == null){
// throw new RuntimeException("@AddJaxRs annotation should be used only with @DisableDiscovery annotation.");
// }
//
// List<? extends Class<?>> beans = classLevelBeans.stream().map(AddBean::value).toList();
// if (beans.contains(org.glassfish.jersey.weld.se.WeldRequestScope.class)) {
// throw new RuntimeException("@AddJaxRs annotation already includes `WeldRequestScope` bean");
// }
//
// List<? extends Class<?>> extensions = classLevelExtensions.stream().map(AddExtension::value).toList();
// if (!extensions.isEmpty()) {
// if (extensions.contains(org.glassfish.jersey.ext.cdi1x.internal.ProcessAllAnnotatedTypes.class)) {
// throw new RuntimeException("@AddJaxRs annotation already includes `ProcessAllAnnotatedTypes` extension");
// }
// if (extensions.contains(CdiExtension.class)) {
// throw new RuntimeException("@AddJaxRs annotation already includes `CDI` extension");
// }
// }
//
// }
}

private boolean hasHelidonTestAnnotation(AnnotatedElement element) {
Expand Down Expand Up @@ -370,7 +361,7 @@ private void startContainer(List<AddBean> beanAnnotations,
initializer.disableDiscovery();
}

initializer.addExtensions(new AddBeansExtension(testClass, beanAnnotations));
initializer.addExtensions(new AddBeansExtension(testClass, beanAnnotations, getFeatureBeans(testClass)));

for (AddExtension addExtension : extensionAnnotations) {
Class<? extends Extension> extensionClass = addExtension.value();
Expand All @@ -382,6 +373,8 @@ private void startContainer(List<AddBean> beanAnnotations,
}
}

getFeatureExtensions(testClass).forEach(initializer::addExtensions);

container = initializer.initialize();
}

Expand Down Expand Up @@ -523,12 +516,14 @@ private void callAfterStop() {
private static class AddBeansExtension implements Extension {
private final Class<?> testClass;
private final List<AddBean> addBeans;
private final List<Class<?>> featureBeans;

private final HashMap<String, Annotation> socketAnnotations = new HashMap<>();

private AddBeansExtension(Class<?> testClass, List<AddBean> addBeans) {
private AddBeansExtension(Class<?> testClass, List<AddBean> addBeans, List<Class<?>> featureBeans) {
this.testClass = testClass;
this.addBeans = addBeans;
this.featureBeans = featureBeans;
}


Expand Down Expand Up @@ -603,6 +598,8 @@ void registerAddedBeans(@Observes BeforeBeanDiscovery event) {
configurator.add(scope);
}
}

featureBeans.forEach(e -> event.addAnnotatedType(e, e.getName()));
}

private boolean hasBda(Class<?> value) {
Expand Down

0 comments on commit 836e6bf

Please sign in to comment.