Skip to content

Commit

Permalink
Use @Inject for resource injection in Sagas
Browse files Browse the repository at this point in the history
The SimpleResourceInjector now uses @Inject annotations to find fields and method setters to inject dependencies instead of searching for a method starting with "set".

Issue #AXON-313 Fixed
  • Loading branch information
stevenb committed Apr 15, 2016
1 parent 81d5444 commit 4639549
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 41 deletions.
Expand Up @@ -45,10 +45,24 @@ private AnnotationUtils() {
* @param <T> The generic type of the annotation
* @return the annotation, or <code>null</code> if no such annotation is present.
*/
@SuppressWarnings("unchecked")
public static <T extends Annotation> T findAnnotation(AnnotatedElement element, Class<T> annotationType) {
T ann = element.getAnnotation(annotationType);
return (T) findAnnotation(element, annotationType.getName());
}

/**
* Find an annotation of given <code>annotationType</code> as String on the given <code>element</code>,
* considering that the given <code>annotationType</code> may be present as a meta annotation on any other
* annotation on that element.
*
* @param element The element to inspect
* @param annotationType The type of annotation as String to find
* @return the annotation, or <code>null</code> if no such annotation is present.
*/
public static Annotation findAnnotation(AnnotatedElement element, String annotationType) {
Annotation ann = getAnnotation(element, annotationType);
if (ann == null) {
HashSet<Class<? extends Annotation>> visited = new HashSet<>();
Set<String> visited = new HashSet<>();
for (Annotation metaAnn : element.getAnnotations()) {
ann = getAnnotation(metaAnn.annotationType(), annotationType, visited);
if (ann != null) {
Expand Down Expand Up @@ -146,10 +160,10 @@ private static <T extends Annotation> void collectAttributes(T ann, Map<String,
}
}

private static <T extends Annotation> T getAnnotation(Class<? extends Annotation> target, Class<T> annotationType,
Set<Class<? extends Annotation>> visited) {
T ann = target.getAnnotation(annotationType);
if (ann == null && visited.add(target)) {
private static Annotation getAnnotation(Class<? extends Annotation> target, String annotationType,
Set<String> visited) {
Annotation ann = getAnnotation(target, annotationType);
if (ann == null && visited.add(target.getName())) {
for (Annotation metaAnn : target.getAnnotations()) {
ann = getAnnotation(metaAnn.annotationType(), annotationType, visited);
if (ann != null) {
Expand All @@ -159,4 +173,5 @@ private static <T extends Annotation> T getAnnotation(Class<? extends Annotation
}
return ann;
}

}
Expand Up @@ -17,15 +17,20 @@
package org.axonframework.saga;

import org.axonframework.common.ReflectionUtils;
import org.axonframework.common.annotation.AnnotationUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Optional;
import java.util.stream.StreamSupport;

import static org.axonframework.common.ReflectionUtils.fieldsOf;
import static org.axonframework.common.ReflectionUtils.methodsOf;

/**
Expand Down Expand Up @@ -60,30 +65,52 @@ public SimpleResourceInjector(Collection<?> resources) {

@Override
public void injectResources(Saga saga) {
for (Method method : methodsOf(saga.getClass())) {
if (isSetter(method)) {
Class<?> requiredType = method.getParameterTypes()[0];
for (Object resource : resources) {
if (requiredType.isInstance(resource)) {
injectResource(saga, method, resource);
}
}
}
injectFieldResources(saga);
injectMethodResources(saga);
}

private void injectFieldResources(Saga saga) {
fieldsOf(saga.getClass()).forEach(field -> {
Optional.ofNullable(AnnotationUtils.findAnnotation(field, "javax.inject.Inject"))
.ifPresent(annotatedFields -> {
Class<?> requiredType = field.getType();
StreamSupport.stream(resources.spliterator(), false)
.filter(requiredType::isInstance)
.forEach(resource -> injectFieldResource(saga, field, resource));
});
});
}

private void injectFieldResource(Saga saga, Field injectField, Object resource) {
try {
ReflectionUtils.ensureAccessible(injectField);
injectField.set(saga, resource);
} catch (IllegalAccessException e) {
logger.warn("Unable to inject resource. Exception while setting field: ", e);
}
}

private void injectResource(Saga saga, Method setterMethod, Object resource) {
private void injectMethodResources(Saga saga) {
methodsOf(saga.getClass()).forEach(method -> {
Optional.ofNullable(AnnotationUtils.findAnnotation(method, "javax.inject.Inject"))
.ifPresent(annotatedMethods -> {
Class<?> requiredType = method.getParameterTypes()[0];
StreamSupport.stream(resources.spliterator(), false)
.filter(requiredType::isInstance)
.forEach(resource -> injectMethodResource(saga, method, resource));
});
});
}

private void injectMethodResource(Saga saga, Method injectMethod, Object resource) {
try {
ReflectionUtils.ensureAccessible(setterMethod);
setterMethod.invoke(saga, resource);
ReflectionUtils.ensureAccessible(injectMethod);
injectMethod.invoke(saga, resource);
} catch (IllegalAccessException e) {
logger.warn("Unable to inject resource. Exception while invoking setter: ", e);
} catch (InvocationTargetException e) {
logger.warn("Unable to inject resource. Exception while invoking setter: ", e.getCause());
}
}

private boolean isSetter(Method method) {
return method.getParameterTypes().length == 1 && method.getName().startsWith("set");
}
}
@@ -1,5 +1,5 @@
org.axonframework.serializer.converters.ByteArrayToInputStreamConverter
org.axonframework.serializer.converters.BlobToInputStreamConverter
org.axonframework.serializer.converters.InputStreamToByteArrayConverter
org.axonframework.serializer.converters.ByteArrayToStringConverter
org.axonframework.serializer.converters.ByteArrayToInputStreamConverter
org.axonframework.serializer.converters.BlobToInputStreamConverter
org.axonframework.serializer.converters.InputStreamToByteArrayConverter
org.axonframework.serializer.converters.ByteArrayToStringConverter
org.axonframework.serializer.converters.StringToByteArrayConverter
Expand Up @@ -21,6 +21,8 @@
import org.axonframework.testutils.MockException;
import org.junit.Test;

import javax.inject.Inject;

import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;

Expand All @@ -32,31 +34,56 @@ public class SimpleResourceInjectorTest {
private SimpleResourceInjector testSubject;

@Test
public void testInjectResource() {
final SomeResource resource = new SomeResource();
testSubject = new SimpleResourceInjector(resource);
public void testInjectFieldResource() throws Exception {
SomeFieldResource expectedFieldResource = new SomeFieldResource();
testSubject = new SimpleResourceInjector(expectedFieldResource);
final StubSaga saga = new StubSaga();
testSubject.injectResources(saga);

assertNull(saga. getSomeWeirdResource());
assertSame(resource, saga.getSomeResource());
assertNull(saga.getSomeWeirdResource());
assertSame(expectedFieldResource, saga.getSomeFieldResource());
}

@Test
public void testInjectMethodResource() {
final SomeMethodResource expectedMethodResource = new SomeMethodResource();
testSubject = new SimpleResourceInjector(expectedMethodResource);
final StubSaga saga = new StubSaga();
testSubject.injectResources(saga);

assertNull(saga.getSomeWeirdResource());
assertSame(expectedMethodResource, saga.getSomeMethodResource());
}

@Test
public void testInjectFieldAndMethodResources() throws Exception {
final SomeFieldResource expectedFieldResource = new SomeFieldResource();
final SomeMethodResource expectedMethodResource = new SomeMethodResource();
testSubject = new SimpleResourceInjector(expectedFieldResource, expectedMethodResource);
final StubSaga saga = new StubSaga();
testSubject.injectResources(saga);

assertNull(saga.getSomeWeirdResource());
assertSame(expectedFieldResource, saga.getSomeFieldResource());
assertSame(expectedMethodResource, saga.getSomeMethodResource());
}

@Test
public void testInjectResource_ExceptionsIgnored() {
final SomeResource resource = new SomeResource();
final SomeMethodResource resource = new SomeMethodResource();
testSubject = new SimpleResourceInjector(resource, new SomeWeirdResource());
final StubSaga saga = new StubSaga();
testSubject.injectResources(saga);

assertNull(saga. getSomeWeirdResource());
assertSame(resource, saga.getSomeResource());
assertNull(saga.getSomeWeirdResource());
assertSame(resource, saga.getSomeMethodResource());
}


private static class StubSaga implements Saga {

private SomeResource someResource;
@Inject
private SomeFieldResource someFieldResource;
private SomeMethodResource someMethodResource;
private SomeWeirdResource someWeirdResource;

@Override
Expand All @@ -78,12 +105,17 @@ public boolean isActive() {
return true;
}

public void setSomeResource(SomeResource someResource) {
this.someResource = someResource;
public SomeFieldResource getSomeFieldResource() {
return someFieldResource;
}

public SomeMethodResource getSomeMethodResource() {
return someMethodResource;
}

public SomeResource getSomeResource() {
return someResource;
@Inject
public void setSomeMethodResource(SomeMethodResource someMethodResource) {
this.someMethodResource = someMethodResource;
}

public SomeWeirdResource getSomeWeirdResource() {
Expand All @@ -93,12 +125,16 @@ public SomeWeirdResource getSomeWeirdResource() {
public void setSomeWeirdResource(SomeWeirdResource someWeirdResource) {
throw new MockException();
}

}

private static class SomeWeirdResource {
private static class SomeFieldResource {
}

private static class SomeMethodResource {
}
private static class SomeResource {

private static class SomeWeirdResource {
}

}

0 comments on commit 4639549

Please sign in to comment.