Skip to content

Commit

Permalink
Merge pull request #30917 from manovotn/eventPayloadValidation
Browse files Browse the repository at this point in the history
Arc - validate Event#select and Event#fire methods for type variables
  • Loading branch information
manovotn authored Feb 8, 2023
2 parents 8c1937f + eb0bd36 commit e6760e8
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,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 Expand Up @@ -200,6 +204,14 @@ private Type getEventType(Class<?> runtimeType) {
new HierarchyDiscovery(canonicalEventType).getResolver().getResolvedTypeVariables()).build();
resolvedType = objectTypeResolver.resolveType(canonicalEventType);
}
/*
* If the runtime type of the event object still contains an unresolved type variable,
* the container must throw an IllegalArgumentException.
*/
if (Types.containsTypeVariable(resolvedType)) {
throw new IllegalArgumentException(
"CDI event payload cannot contain unresolved type variable; found type: " + resolvedType);
}
return resolvedType;
}

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 e6760e8

Please sign in to comment.