Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/constructor level injection #126

Merged
merged 19 commits into from
Jun 2, 2017

Conversation

AFrieze
Copy link
Collaborator

@AFrieze AFrieze commented Apr 19, 2017

Added constructor injection for consumers.

Note: I thought about pulling this functionality out into its own set of classes, or even incorporating an existing DI framework. I decided that was a bit more than I wanted to take on right now and kept code changes to a minimum. Could be considerations for the future though.

@@ -0,0 +1 @@
/Applications/activator-dist-1.3.7/repository/com.google.guava/guava/18.0/bundles/guava.jar:/Users/afrieze/.ivy2/cache/com.fasterxml.jackson.core/jackson-databind/bundles/jackson-databind-2.7.3.jar:/Users/afrieze/.ivy2/cache/com.fasterxml.jackson.core/jackson-annotations/bundles/jackson-annotations-2.7.0.jar:/Users/afrieze/.ivy2/cache/com.fasterxml.jackson.core/jackson-core/bundles/jackson-core-2.7.3.jar:/Users/afrieze/.ivy2/cache/com.fasterxml.jackson.datatype/jackson-datatype-jsr310/bundles/jackson-datatype-jsr310-2.7.3.jar:/Users/afrieze/.ivy2/cache/ch.qos.logback/logback-classic/jars/logback-classic-1.0.13.jar:/Users/afrieze/.ivy2/cache/ch.qos.logback/logback-core/jars/logback-core-1.0.13.jar:/Users/afrieze/.ivy2/cache/org.slf4j/slf4j-api/jars/slf4j-api-1.7.5.jar:/Users/afrieze/.ivy2/cache/org.reflections/reflections/jars/reflections-0.9.10.jar:/Applications/activator-dist-1.3.7/repository/org.javassist/javassist/3.18.2-GA/bundles/javassist.jar:/Users/afrieze/.ivy2/cache/com.google.code.findbugs/annotations/jars/annotations-2.0.1.jar:/Applications/activator-dist-1.3.7/repository/javax.inject/javax.inject/1/jars/javax.inject.jar
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be ignored or deleted, right?

public void jsonConstructorInjection() throws Exception {
ConsumerService service = new ConsumerService(ServiceBeanResolver.class);
Consumer test = new Consumer(ConstructorJsonConsumer.class, forklift, this.getClass().getClassLoader());
test.setServices(Arrays.asList(service));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a little cleaner as addServices

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: Also, maybe it'd be nice to test service-based injection separately from forklift-based injection

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's worth considering a refactor where the injection code is removed from the consumer entirely(this is what I started to do initially).

The setServices method was already in place and I tried to stick with adding the new functionality and not go down a refactoring rabbit hole.

@@ -1,15 +1,18 @@
package forklift;
package forklift.consumer.injection;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, it's not all injection tests!

@@ -213,7 +222,7 @@ else if (queue != null)
log.info("Creating thread pool of {}", multiThreaded.value());
blockQueue = new ArrayBlockingQueue<>(multiThreaded.value() * 100 + 100);
threadPool = new ThreadPoolExecutor(
multiThreaded.value(), multiThreaded.value(), 5L, TimeUnit.MINUTES, blockQueue);
multiThreaded.value(), multiThreaded.value(), 5L, TimeUnit.MINUTES, blockQueue);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That indentation seems a bit excessive.

Constructor<?>[] constructors = msgHandler.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
if (constructor.isAnnotationPresent(Inject.class)) {
this.constructor = constructor;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe worth it to log an error or warning (realistically, logging an error is more immediately useful) when there are multiple constructors annotated with @Inject?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Object[] parameters = new Object[constructorAnnotations.length];
int index = 0;
for (Annotation[] parameterAnnotations : constructorAnnotations) {
//there must be at least one annotation that indicates what we should inject
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except not, right? If there's no annotation you still handle it fine by treating it like it has Inject

// Try to resolve the class from any available BeanResolvers.
for (ConsumerService s : this.services) {
try {
final Object o = s.resolve(mappedClass, null);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we don't want name-based resolution? I guess it's worked so far, but isn't it a bit limiting to be unable to distinguish objects of the same type?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm avoiding making changes to the existing functionality.

break;
}
} catch (Exception e) {
log.debug("", e);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this was existing code, but aren't errors like "failed to autowire dependency" pretty useful?

public Class<?> getMsgHandler() {
return msgHandler;
}

/**
* Creates an instance of hte MessageHandler class utilized by this constructor. Constructor and Field level injection is performed using both the
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"hte"

@@ -242,11 +251,12 @@ public void messageLoop(ForkliftConsumerI consumer) {
ForkliftMessage consumerMsg;
while ((consumerMsg = consumer.receive(2500)) != null && running.get()) {
try {
final Object handler = msgHandler.newInstance();

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really a fan of newlines at the start of a block


/**
* Inject the data from a forklift message into an instance of the msgHandler class.
* @param msg containing data
*
* @param msg containing data
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't really improve the vague documentation to add some spaces

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the space is to align with the param below that isn't shown :(

return parameters;
}

private Object getInjectableValue(Annotation decorator, String mappedName, Class<?> mappedClass, ForkliftMessage msg) throws IOException {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thought for later: maybe this could be separated out better with a map of handlers or something

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

@@ -362,112 +384,12 @@ public void setOutOfMessages(java.util.function.Consumer<Consumer> outOfMessages
fields.get(clazz).forEach(f -> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we take this opportunity to not call this variable f?

*
* @param msg
*/
public Object getMsgHandlerInstance(ForkliftMessage msg) throws InvocationTargetException, IOException, InstantiationException, IllegalAccessException {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this method just public for internal testing, or what?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Copying how the inject method and testing works.

*
* @param msg
*/
public Object getMsgHandlerInstance(ForkliftMessage msg) throws InvocationTargetException, IOException, InstantiationException, IllegalAccessException {
Copy link
Collaborator

@Kuroshii Kuroshii Apr 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't imagine most callers to these methods having a meaningful way of handling all of these exceptions differently. Maybe just wrap them in one exception?

Probably even let it be unchecked; 'cause fail-fast

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. The "Inject" method throws a runtime exception so I'l do the same

Copy link
Collaborator

@Kuroshii Kuroshii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly just some minor nits; with a few changes should be good to go.

Copy link
Collaborator

@Kuroshii Kuroshii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

P.S. But there's still an indentation problem, please fix it

@Kuroshii Kuroshii force-pushed the feature/constructor-level-injection branch from cee304d to 1ad6e4f Compare June 2, 2017 20:14
@Kuroshii Kuroshii merged commit 4ddd0da into develop Jun 2, 2017
@Kuroshii Kuroshii deleted the feature/constructor-level-injection branch June 9, 2017 21:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants