Skip to content

Commit

Permalink
WELD-2639 Allow to expand set of BDA via generic properties.
Browse files Browse the repository at this point in the history
  • Loading branch information
manovotn committed Nov 30, 2020
1 parent 4207e6f commit 95fdabd
Show file tree
Hide file tree
Showing 3 changed files with 201 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,14 @@
@Vetoed
public class Weld extends SeContainerInitializer implements ContainerInstanceFactory {

/**
* By default, the set of bean-defining annotations is fixed. If set to a {@link Set} of annotation classes, the set of bean-defining annotations is
* augmented with the contents of the {@link Set}.
* <p>
* This key can be used through {@link #property(String, Object}.
*/
public static final String ADDITIONAL_BEAN_DEFINING_ANNOTATIONS_PROPERTY = "org.jboss.weld.se.additionalBeanDefiningAnnotations";

/**
* By default, bean archive isolation is enabled. If set to false, Weld will use a "flat" deployment structure - all bean classes share the same bean
* archive and all beans.xml descriptors are automatically merged into one.
Expand Down Expand Up @@ -774,6 +782,8 @@ public WeldContainer initialize() {
}

final WeldBootstrap bootstrap = new WeldBootstrap();
// load possible additional BDA
parseAdditionalBeanDefiningAnnotations();
final Deployment deployment = createDeployment(resourceLoader, bootstrap);

final ExternalConfigurationBuilder configurationBuilder = new ExternalConfigurationBuilder()
Expand All @@ -786,7 +796,8 @@ public WeldContainer initialize() {
for (Entry<String, Object> property : properties.entrySet()) {
String key = property.getKey();
if (SHUTDOWN_HOOK_SYSTEM_PROPERTY.equals(key) || ARCHIVE_ISOLATION_SYSTEM_PROPERTY.equals(key) || DEV_MODE_SYSTEM_PROPERTY.equals(key)
|| SCAN_CLASSPATH_ENTRIES_SYSTEM_PROPERTY.equals(key) || JAVAX_ENTERPRISE_INJECT_SCAN_IMPLICIT.equals(key)) {
|| SCAN_CLASSPATH_ENTRIES_SYSTEM_PROPERTY.equals(key) || JAVAX_ENTERPRISE_INJECT_SCAN_IMPLICIT.equals(key)
|| ADDITIONAL_BEAN_DEFINING_ANNOTATIONS_PROPERTY.equals(key)) {
continue;
}
configurationBuilder.add(key, property.getValue());
Expand Down Expand Up @@ -1214,6 +1225,49 @@ protected Object getPropertyValue(String key, Object defaultValue) {
return defaultValue;
}

/**
* Parses additional bean defining annotations from either system properties, or SE container properties.
*/
private void parseAdditionalBeanDefiningAnnotations() {
// parse additional bean defining annotations from SE container properties
if (properties.containsKey(ADDITIONAL_BEAN_DEFINING_ANNOTATIONS_PROPERTY)) {
Object valueObj = properties.get(ADDITIONAL_BEAN_DEFINING_ANNOTATIONS_PROPERTY);
if (valueObj instanceof Collection) {
for (Object element : ((Collection<?>) valueObj)) {
if (element instanceof Class<?> && Annotation.class.isAssignableFrom((Class<?>) element)) {
extendedBeanDefiningAnnotations.add((Class<? extends Annotation>) element);
} else {
// one of the values is not an annotation, log warning
WeldSELogger.LOG.unexpectedItemsInValueCollection(element.getClass());
}
}
} else {
// value is not a collection, throw IAE
throw WeldSELogger.LOG.unexpectedValueForAdditionalBeanDefiningAnnotations(valueObj.getClass());
}
}

// parse from system properties
String stringValue = AccessController.doPrivileged(new GetSystemPropertyAction(ADDITIONAL_BEAN_DEFINING_ANNOTATIONS_PROPERTY));
if (stringValue != null) {
for (String className : stringValue.split(",")) {
if (!className.isEmpty()) {
try {
Class<?> loadedClass = Class.forName(className);
if (loadedClass.isAnnotation()) {
extendedBeanDefiningAnnotations.add((Class<? extends Annotation>) loadedClass);
} else {
// one of the values is not an annotation, log warning
WeldSELogger.LOG.unexpectedItemsInValueCollection(loadedClass);
}
} catch (LinkageError | ClassNotFoundException e) {
throw WeldSELogger.LOG.failedToLoadClass(className, e.toString());
}
}
}
}
}

private static class PackInfo {

private final String packName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,15 @@ public interface WeldSELogger extends WeldEnvironmentLogger {

@Message(id = 2016, value = "Zero or more than one container is running - WeldContainer.current() cannot determine the current container.", format = Format.MESSAGE_FORMAT)
IllegalStateException zeroOrMoreThanOneContainerRunning();

@Message(id = 2017, value = "Unexpected value for parameter 'org.jboss.weld.se.additionalBeanDefiningAnnotations'. Expected java.util.Collection but found {0}. ", format = Format.MESSAGE_FORMAT)
IllegalArgumentException unexpectedValueForAdditionalBeanDefiningAnnotations(Class clazz);

@LogMessage(level = Level.WARN)
@Message(id = 2018, value = "Skipping registration of additional bean defining annotation via `org.jboss.weld.se.additionalBeanDefiningAnnotations`. " +
"Only values of type Class<? extends Annotation> are valid. Found: {0}", format = Format.MESSAGE_FORMAT)
void unexpectedItemsInValueCollection(Class clazz);

@Message(id = 2019, value = "Failed to parse the following string as additional bean defining annotation: {0}. The exception was: {1}", format = Format.MESSAGE_FORMAT)
IllegalArgumentException failedToLoadClass(String className, String exception);
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,19 @@
import org.junit.Test;
import org.junit.runner.RunWith;

import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;

/**
* Adds new bean defining annotations in Weld SE, then leaves discovery on and asserts that beans were found.
*
* Also tests that you can add new BDA via purely CDI SE container properties and via system properties.
*
* @see WELD-2523
* @see WELD-2639
*
* @author <a href="mailto:manovotn@redhat.com">Matej Novotny</a>
*/
Expand Down Expand Up @@ -60,4 +69,130 @@ public void testNewBeanDefiningAnnotationWorks() {
}
}

@Test
public void testDeclarationViaPropertiesWithWrongValue() {
Weld weld = new Weld()
.disableDiscovery()
.setBeanDiscoveryMode(BeanDiscoveryMode.ANNOTATED)
.addPackages(Bar.class.getPackage())
.addProperty(Weld.ADDITIONAL_BEAN_DEFINING_ANNOTATIONS_PROPERTY, "foo");

try (WeldContainer container = weld.initialize()) {
// should throw up while booting
Assert.fail();
} catch (IllegalArgumentException expected) {
// OK
}
}

@Test
public void testDeclarationViaPropertiesWithCorruptedSet() {
// we log warning on each wrong item in the list, so this should pass and just skip wrong value
Set<Object> corruptedSet = new HashSet<>();
corruptedSet.add(NewBeanDefiningAnnotation.class);
corruptedSet.add(1l);

Weld weld = new Weld()
.disableDiscovery()
.setBeanDiscoveryMode(BeanDiscoveryMode.ANNOTATED)
.addPackages(Bar.class.getPackage())
.addProperty(Weld.ADDITIONAL_BEAN_DEFINING_ANNOTATIONS_PROPERTY, corruptedSet);

try (WeldContainer container = weld.initialize()) {
Assert.assertTrue(container.isRunning());
Assert.assertTrue(container.select(Foo.class).isResolvable());
Assert.assertTrue(container.select(Bar.class).isResolvable());
}
}

@Test
public void testCorrectDeclarationViaProperties() {
// we log warning on each wrong item in the list, so this should pass and just skip wrong value
Set<Class<? extends Annotation>> correctSet = new HashSet<>();
correctSet.add(NewBeanDefiningAnnotation.class);

Weld weld = new Weld()
.disableDiscovery()
.setBeanDiscoveryMode(BeanDiscoveryMode.ANNOTATED)
.addPackages(Bar.class.getPackage())
.addProperty(Weld.ADDITIONAL_BEAN_DEFINING_ANNOTATIONS_PROPERTY, correctSet);

try (WeldContainer container = weld.initialize()) {
Assert.assertTrue(container.isRunning());
Assert.assertTrue(container.select(Foo.class).isResolvable());
Assert.assertTrue(container.select(Bar.class).isResolvable());
}
}

@Test
public void testCorrectDeclarationViaSystemProperties() {
setupSystemProperty(true, false, false);
Weld weld = new Weld()
.disableDiscovery()
.setBeanDiscoveryMode(BeanDiscoveryMode.ANNOTATED)
.addPackages(Bar.class.getPackage());

try (WeldContainer container = weld.initialize()) {
Assert.assertTrue(container.isRunning());
Assert.assertTrue(container.select(Foo.class).isResolvable());
Assert.assertTrue(container.select(Bar.class).isResolvable());
} finally {
clearSystemProperty();
}
}

@Test
public void testDeclarationViaSystemPropertiesWithCorruptedList() {
setupSystemProperty(true, true, false);
Weld weld = new Weld()
.disableDiscovery()
.setBeanDiscoveryMode(BeanDiscoveryMode.ANNOTATED)
.addPackages(Bar.class.getPackage());

try (WeldContainer container = weld.initialize()) {
Assert.assertTrue(container.isRunning());
Assert.assertTrue(container.select(Foo.class).isResolvable());
Assert.assertTrue(container.select(Bar.class).isResolvable());
} finally {
clearSystemProperty();
}
}

@Test
public void testDeclarationViaSystemPropertiesWithWrongValue() {
setupSystemProperty(true, false, true);
Weld weld = new Weld()
.disableDiscovery()
.setBeanDiscoveryMode(BeanDiscoveryMode.ANNOTATED)
.addPackages(Bar.class.getPackage());

try (WeldContainer container = weld.initialize()) {
Assert.fail();
} catch (IllegalArgumentException expected) {
// OK, this should blow up
System.err.println(expected);
} finally {
clearSystemProperty();
}
}

private void setupSystemProperty(boolean correctClass, boolean wrongType, boolean nonExistentClass) {
Properties props = System.getProperties();
StringBuilder builder = new StringBuilder();
if (correctClass) {
builder.append(NewBeanDefiningAnnotation.class.getName()).append(",");
}
if (wrongType) {
builder.append(Integer.class.getName()).append(",");
}
if (nonExistentClass) {
builder.append("foo.bar.Nope");
}
props.setProperty(Weld.ADDITIONAL_BEAN_DEFINING_ANNOTATIONS_PROPERTY, builder.toString());
}

private void clearSystemProperty() {
Properties props = System.getProperties();
props.remove(Weld.ADDITIONAL_BEAN_DEFINING_ANNOTATIONS_PROPERTY);
}
}

0 comments on commit 95fdabd

Please sign in to comment.