Skip to content

Commit

Permalink
Create throwing handler
Browse files Browse the repository at this point in the history
  • Loading branch information
P3ridot committed Jul 17, 2023
1 parent 1e67380 commit f646773
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 17 deletions.
8 changes: 8 additions & 0 deletions di/src/main/java/org/panda_lang/utilities/inject/Bind.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.panda_lang.utilities.inject;

import org.jetbrains.annotations.NotNull;
import panda.std.function.ThrowingTriFunction;
import panda.std.function.TriFunction;
import java.lang.annotation.Annotation;
import java.util.function.Supplier;
Expand Down Expand Up @@ -44,6 +45,13 @@ public interface Bind<A extends Annotation> extends Comparable<Bind<A>> {
*/
void assignHandler(TriFunction<Property, A, Object[], ?> handler);

/**
* Assign custom handler to the bind which can throw an exception
*
* @param handler the handler which accepts type of parameter and bind type as arguments
*/
void assignThrowingHandler(ThrowingTriFunction<Property, A, Object[], ?, ? extends Exception> handler);

/**
* Get the value of bind for the required (parameter) type and instance of a bind type
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.panda_lang.utilities.inject;

import panda.std.function.ThrowingTriFunction;
import panda.std.function.TriFunction;
import panda.utilities.ObjectUtils;
import java.lang.annotation.Annotation;
Expand Down Expand Up @@ -59,6 +60,11 @@ public void assignHandler(TriFunction<Property, A, Object[], ?> handler) {
with(new HandledBindValue<>(handler));
}

@Override
public void assignThrowingHandler(ThrowingTriFunction<Property, A, Object[], ?, ? extends Exception> handler) {
with(new HandledBindValue<>(handler));
}

@Override
public Object getValue(Property required, A annotation, Object... injectedArgs) throws Exception {
return this.value.getValue(required, annotation, injectedArgs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,24 @@

package org.panda_lang.utilities.inject;

import panda.std.function.ThrowingTriFunction;
import panda.std.function.TriFunction;
import java.lang.annotation.Annotation;

final class HandledBindValue<A extends Annotation> implements BindValue<A> {

private final TriFunction<Property, A, Object[], ?> handler;
private final ThrowingTriFunction<Property, A, Object[], ?, ? extends Exception> handler;

HandledBindValue(TriFunction<Property, A, Object[], ?> handler) {
HandledBindValue(ThrowingTriFunction<Property, A, Object[], ?, ? extends Exception> handler) {
this.handler = handler;
}

HandledBindValue(TriFunction<Property, A, Object[], ?> handler) {
this.handler = handler::apply;
}

@Override
public Object getValue(Property required, A annotation, Object... injectorArgs) {
public Object getValue(Property required, A annotation, Object... injectorArgs) throws Exception {
return handler.apply(required, annotation, injectorArgs);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,7 @@ final class InjectorProcessor {
this.injector = injector;

this.autoConstructBind = new DefaultBind<>(AutoConstruct.class);
this.autoConstructBind.assignHandler((property, annotation, injectorArgs) -> {
try {
return injector.newInstanceWithFields(property.getType(), injectorArgs);
} catch (Exception ex) {
throw new DependencyInjectionException(ex);
}
});
this.autoConstructBind.assignThrowingHandler((property, annotation, injectorArgs) -> injector.newInstanceWithFields(property.getType(), injectorArgs));
}

protected Object[] fetchValues(InjectorCache cache, Object... injectorArgs) throws Exception {
Expand Down Expand Up @@ -170,8 +164,13 @@ protected Bind<Annotation>[] fetchBinds(Annotation[] annotations, Executable exe
}

protected Bind<Annotation> fetchBind(@Nullable Annotation annotation, Property property) throws MissingBindException {
Class<?> requiredType = annotation != null ? annotation.annotationType() : property.getType();
Bind<Annotation> bind = this.injector.getResources().getBind(requiredType).orNull();
Bind<Annotation> bind = annotation != null
? this.injector.getResources().getBind(annotation.annotationType()).orNull()
: null;

if (bind == null) {
bind = this.injector.getResources().getBind(property.getType()).orNull();
}
if (bind == null && property.getAnnotation(AutoConstruct.class) != null) {
bind = this.autoConstructBind;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public String serveAbstract() {
}

@Test
void shouldInjectFields() throws Throwable {
void shouldInjectFields() {
Injector injector = DependencyInjection.createInjector(resources -> {
resources.on(boolean.class).assignInstance(true);
resources.on(String.class).assignInstance("Hello Field");
Expand All @@ -68,7 +68,7 @@ void shouldInjectFields() throws Throwable {
resources.annotatedWithTested(Custom.class).assignHandler((property, custom, objects) -> objects[0].toString());
});

Service service = injector.forFields(Service.class).newInstance("custom argument");
Service service = injector.newInstanceWithFields(Service.class,"custom argument");
assertEquals("Hello Field 7", service.serve());
assertEquals("1.2 254623242914889729", service.serveAbstract());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package org.panda_lang.utilities.inject;

import org.junit.jupiter.api.Test;
import org.panda_lang.utilities.inject.annotations.Inject;
import org.panda_lang.utilities.inject.annotations.Injectable;
import org.panda_lang.utilities.inject.annotations.PostConstruct;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.ThreadLocalRandom;

import static org.junit.jupiter.api.Assertions.*;

public class DependencyInjectionHandlerTest {

@Injectable
@Retention(RetentionPolicy.RUNTIME)
@interface Custom {
}

@Injectable
@Retention(RetentionPolicy.RUNTIME)
@interface AwesomeRandom {
}

public static class Service1 {
@Inject
@Custom
public String fieldOne;

@Inject
public int fieldTwo;

@Inject
@AwesomeRandom
public int fieldThree;

@PostConstruct
public void construct() {
assertEquals("HelloWorld", this.fieldOne);

assertEquals(7, this.fieldTwo);
assertTrue(this.fieldTwo >= 2 && this.fieldTwo <= 10);
}
}

@Test
void shouldCreateInstance() {
Injector injector = DependencyInjection.createInjector(resources -> {
resources.annotatedWith(Custom.class).assignHandler((type, annotation, args) -> "HelloWorld");
resources.on(int.class).assignHandler((type, annotation, args) -> {
AwesomeRandom randomAnnotation = type.getAnnotation(AwesomeRandom.class);
if (randomAnnotation == null) {
return 7;
}
return ThreadLocalRandom.current().nextInt(2, 10);
});
});

injector.newInstanceWithFields(Service1.class);
}

public static class Service2 {
@Inject
public String fieldOne;
}

@Test
void shouldNotCreateInstance() {
Injector injector = DependencyInjection.createInjector(resources -> {
resources.on(String.class).assignThrowingHandler((type, annotation, args) -> {
throw new Exception("Failed");
});
});
assertThrows(DependencyInjectionException.class, () -> injector.newInstanceWithFields(Service2.class));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
final class DependencyInjectionInstancesTest {

@Test
void shouldInjectInstances() throws Throwable {
void shouldInjectInstances() {
Injector injector = DependencyInjection.createInjector();

// some logic, a few hours later...

injector.getResources().on(Custom.class).assignInstance(new CustomImpl()); // singleton
injector.getResources().on(Bean.class).assignInstance(Bean::new); // new instance per call

Service service = injector.forConstructor(Service.class).newInstance();
Service service = injector.newInstance(Service.class);
assertNotNull(service);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
final class DependencyInjectionWikiTest {

@Test
void testWikiExample() throws Throwable {
void testWikiExample() {
Injector injector = DependencyInjection.createInjector(resources -> {
resources.annotatedWith(AwesomeRandom.class).assignHandler((required, annotation, injectorArgs) -> {
Class<?> expectedType = required.getType();
Expand Down

0 comments on commit f646773

Please sign in to comment.