Skip to content

Commit

Permalink
Arc - validate Event#select and Event#fire methods for type variables
Browse files Browse the repository at this point in the history
  • Loading branch information
manovotn committed Feb 7, 2023
1 parent 7c77b28 commit e62c88d
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ class EventImpl<T> implements Event<T> {
@Override
public void fire(T event) {
Objects.requireNonNull(event, "Event cannot be null");
// If the runtime type of the event object contains an unresolved type variable, the container must throw an IllegalArgumentException.
Type eventType = getEventType(event.getClass());
if (Types.containsTypeVariable(eventType)) {
throw new IllegalArgumentException(
"CDI event payload cannot contain unresolved type variable; found type: " + eventType);
}
getNotifier(event.getClass()).notify(event, ObserverExceptionHandler.IMMEDIATE_HANDLER, false);
}

Expand Down Expand Up @@ -133,6 +139,10 @@ public Event<T> select(Annotation... qualifiers) {

@Override
public <U extends T> Event<U> select(Class<U> subtype, Annotation... qualifiers) {
if (Types.containsTypeVariable(subtype)) {
throw new IllegalArgumentException(
"Event#select(Class<U>, Annotation...) cannot be used with type variable parameter");
}
ArcContainerImpl.instance().registeredQualifiers.verify(qualifiers);
Set<Annotation> mergerdQualifiers = new HashSet<>(this.qualifiers);
Collections.addAll(mergerdQualifiers, qualifiers);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.quarkus.arc.test.event.fire;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.arc.Arc;
import io.quarkus.arc.test.ArcTestContainer;

public class EventFireTest {

@RegisterExtension
public ArcTestContainer container = new ArcTestContainer();

@Test
public <T> void testEventFireThrowsExceptionIfEventTypeHasTypeVariable() {
Assertions.assertThrows(IllegalArgumentException.class,
() -> Arc.container().beanManager().getEvent().select(BarInterface.class).fire(new Foo<T>()),
"Event#fire should throw IllegalArgumentException if the payload contains unresolved type variable");
}

public class Foo<T> implements BarInterface {

}

public interface BarInterface {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,67 +22,56 @@ public class EventSelectTest {

@Test
public <T> void testEventSelectThrowsExceptionIfEventTypeHasTypeVariable() {
try {
SecuritySensor sensor = Arc.container().select(SecuritySensor.class).get();
sensor.securityEvent.select(new TypeLiteral<SecurityEvent_Illegal<T>>() {
});
Assertions.fail("Event#select should throw IllegalArgumentException if the event uses type variable");
} catch (IllegalArgumentException iae) {
// expected
}
SecuritySensor sensor = Arc.container().select(SecuritySensor.class).get();
TypeLiteral<SecurityEvent_Illegal<T>> typeLiteral = new TypeLiteral<SecurityEvent_Illegal<T>>() {
};
Assertions.assertThrows(IllegalArgumentException.class,
() -> {
sensor.securityEvent.select(typeLiteral);
}, "Event#select should throw IllegalArgumentException if the event uses type variable");

// do the same but with raw type passed into select(Class<U> subtype, Annotation ... qualifiers)
Assertions.assertThrows(IllegalArgumentException.class, () -> sensor.securityEvent.select(SecurityEvent_Illegal.class),
"Event#select should throw IllegalArgumentException if the event uses type variable");
}

@Test
public void testEventSelectThrowsExceptionForDuplicateBindingType() {
try {
Assertions.assertThrows(IllegalArgumentException.class, () -> {
SecuritySensor sensor = Arc.container().select(SecuritySensor.class).get();
sensor.securityEvent.select(new SystemTest.SystemTestLiteral("a") {
},
new SystemTest.SystemTestLiteral("b") {
});
Assertions.fail("Event#select should throw IllegalArgumentException when there are duplicate bindings specified.");
} catch (IllegalArgumentException iae) {
// expected
}
}, "Event#select should throw IllegalArgumentException when there are duplicate bindings specified.");
}

@Test
public void testEventSelectWithSubtypeThrowsExceptionForDuplicateBindingType() {
try {
Assertions.assertThrows(IllegalArgumentException.class, () -> {
SecuritySensor sensor = Arc.container().select(SecuritySensor.class).get();
sensor.securityEvent.select(BreakInEvent.class, new SystemTest.SystemTestLiteral("a") {
},
new SystemTest.SystemTestLiteral("b") {
});
Assertions.fail(
"Event#select should throw IllegalArgumentException when selecting a subtype with duplicate bindings.");
} catch (IllegalArgumentException iae) {
// expected
}
}, "Event#select should throw IllegalArgumentException when selecting a subtype with duplicate bindings.");
}

@Test
public void testEventSelectThrowsExceptionIfAnnotationIsNotBindingType() {
try {
Assertions.assertThrows(IllegalArgumentException.class, () -> {
SecuritySensor sensor = Arc.container().select(SecuritySensor.class).get();
sensor.securityEvent.select(new AnnotationLiteral<NotABindingType>() {
});
Assertions.fail("Event#select should throw IllegalArgumentException if the annotation is not a binding type.");
} catch (IllegalArgumentException iae) {
// expected
}
}, "Event#select should throw IllegalArgumentException if the annotation is not a binding type.");
}

@Test
public void testEventSelectWithSubtypeThrowsExceptionIfAnnotationIsNotBindingType() {
try {
Assertions.assertThrows(IllegalArgumentException.class, () -> {
SecuritySensor sensor = Arc.container().select(SecuritySensor.class).get();
sensor.securityEvent.select(BreakInEvent.class, new AnnotationLiteral<NotABindingType>() {
});
Assertions.fail(
"Event#select should throw IllegalArgumentException when selecting a subtype and using annotation that is not a binding type.");
} catch (IllegalArgumentException iae) {
// expected
}
}, "Event#select should throw IllegalArgumentException when selecting a subtype and using annotation that is not a binding type.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import jakarta.annotation.PreDestroy;
import jakarta.enterprise.context.RequestScoped;
import jakarta.enterprise.event.Observes;
import jakarta.enterprise.util.TypeLiteral;
import jakarta.inject.Singleton;

import org.junit.jupiter.api.Test;
Expand All @@ -32,11 +33,12 @@ public class RequestInObserverNotificationTest {
@Test
public void testObserverNotification() {
ArcContainer container = Arc.container();
AtomicReference<String> msg = new AtomicReference<String>();
AtomicReference<String> msg = new AtomicReference<>();
RequestFoo.DESTROYED.set(false);

// Request context should be activated automatically
container.beanManager().getEvent().select(AtomicReference.class).fire(msg);
container.beanManager().getEvent().select(new TypeLiteral<AtomicReference<String>>() {
}).fire(msg);
String fooId1 = msg.get();
assertNotNull(fooId1);
assertTrue(RequestFoo.DESTROYED.get());
Expand All @@ -50,7 +52,8 @@ public void testObserverNotification() {
requestContext.activate();
String fooId2 = container.instance(RequestFoo.class).get().getId();
assertNotEquals(fooId1, fooId2);
container.beanManager().getEvent().select(AtomicReference.class).fire(msg);
container.beanManager().getEvent().select(new TypeLiteral<AtomicReference<String>>() {
}).fire(msg);
assertEquals(fooId2, msg.get());
} finally {
requestContext.terminate();
Expand Down

0 comments on commit e62c88d

Please sign in to comment.