Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import io.avaje.inject.BeanScope;
import io.avaje.inject.Lazy;
import io.avaje.inject.PostConstruct;
import io.avaje.inject.PreDestroy;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.inject.Singleton;
Expand All @@ -17,13 +18,23 @@
public class LazyBean {

@Inject @Nullable AtomicBoolean initialized;
private AtomicBoolean destroyed = new AtomicBoolean(false);

@PostConstruct
void init(BeanScope scope) {
// note that nested test scopes will not be lazy
if (initialized != null) initialized.set(true);
}

@PreDestroy
void shutdown() {
destroyed.set(true);
}

boolean isDestroyed() {
return destroyed.get();
}

void something() {}

public void other() {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ LazyInterface lazyInterFace(@Nullable AtomicBoolean initialized) throws Exceptio
return new LazyImpl(initialized);
}

@Bean
@Bean(destroyMethod = "shutdown")
@BeanTypes(LazyInterface.class)
@Named("factoryBeanType")
LazyImpl factoryBeanType(@Nullable AtomicBoolean initialized) throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
@BeanTypes(LazyInterface.class)
public class LazyImpl implements LazyInterface {

AtomicBoolean initialized;
private AtomicBoolean initialized;
private AtomicBoolean destroyed = new AtomicBoolean(false);

public LazyImpl(@Nullable AtomicBoolean initialized) {
this.initialized = initialized;
Expand All @@ -28,6 +29,15 @@ void init(BeanScope scope) {
if (initialized != null) initialized.set(true);
}

void shutdown() {
destroyed.set(true);
}

@Override
public boolean isDestroyed() {
return destroyed.get();
}

@Override
public void something() {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ public interface LazyInterface {
void something();

void otherThing();

default boolean isDestroyed() {
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ class LazyTest {

@Test
void test() {
LazyBean lazy;
var initialized = new AtomicBoolean();
try (var scope = BeanScope.builder().beans(initialized).build()) {
assertThat(initialized).isFalse();
var lazy = scope.get(LazyBean.class, "single");
lazy = scope.get(LazyBean.class, "single");
assertThat(lazy).isNotNull();
assertThat(initialized).isFalse();
lazy.something();
Expand All @@ -24,6 +25,7 @@ void test() {
var lazyAgain = scope.get(LazyBean.class, "single");
assertThat(lazyAgain).isSameAs(lazy);
}
assertThat(lazy.isDestroyed()).isTrue();
}

@Test
Expand Down Expand Up @@ -71,14 +73,16 @@ void testFactoryInterface() {
@Test
void factoryBeanType() {
var initialized = new AtomicBoolean();
LazyInterface prov;
try (var scope = BeanScope.builder().beans(initialized).build()) {
assertThat(initialized).isFalse();
var prov = scope.get(LazyInterface.class, "factoryBeanType");
prov = scope.get(LazyInterface.class, "factoryBeanType");
assertThat(initialized).isFalse();
prov.something();
assertThat(initialized).isTrue();
assertThat(prov).isNotNull();
}
assertThat(prov.isDestroyed()).isTrue();
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -386,8 +386,7 @@ void addLifecycleCallbacks(Append writer, String indent) {
writePostConstruct(writer, indent, postConstructMethod.get());
}

if (preDestroyMethod != null) {
lifeCycleNotSupported("@PreDestroy");
if (preDestroyMethod != null && !registerProvider()) {
var priority = preDestroyPriority == null || preDestroyPriority == 1000 ? "" : ", " + preDestroyPriority;
writer.indent(indent).append(" builder.addPreDestroy($bean::%s%s);", preDestroyMethod.getSimpleName(), priority).eol();
} else if (typeReader.isClosable() && !prototype) {
Expand All @@ -408,7 +407,7 @@ private void writePostConstruct(Append writer, String indent, MethodReader postC
}
}

void prototypePostConstruct(Append writer, String indent) {
void providerLifeCycle(Append writer, String indent) {
postConstructMethod.ifPresent(m -> {
writer.indent(indent).append(" bean.%s(", m.name());
if (m.params().isEmpty()) {
Expand All @@ -417,11 +416,17 @@ void prototypePostConstruct(Append writer, String indent) {
writeLifeCycleGet(writer, m.params(), "builder", "builder.get(io.avaje.inject.BeanScope.class)");
writer.append(";").eol();
}
writer.eol();
});

if (preDestroyMethod != null) {
writer
.indent(indent)
.append(" builder.addPreDestroy(bean::%s);", preDestroyMethod.getSimpleName())
.eol();
}
}

private void writeLifeCycleGet(Append writer, List<MethodParam> params, String builderName, String beanScopeString) {
static void writeLifeCycleGet(Append writer, List<MethodParam> params, String builderName, String beanScopeString) {
final var size = params.size();
for (int i = 0; i < size; i++) {
if (i > 0) {
Expand All @@ -437,16 +442,6 @@ private void writeLifeCycleGet(Append writer, List<MethodParam> params, String b
writer.append(")");
}

private void lifeCycleNotSupported(String lifecycle) {
if (registerProvider()) {
logError(
beanType,
"%s scoped bean does not support the %s lifecycle method",
prototype ? "@Prototype" : "@Lazy",
lifecycle);
}
}

private Set<String> importTypes() {
importTypes.add(type);
typeReader.extraImports(importTypes);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,44 +1,43 @@
package io.avaje.inject.generator;

import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.ElementFilter;

/**
* Looks for lifecycle annotations on methods.
*/
/** Looks for lifecycle annotations on methods. */
final class MethodLifecycleReader {

private final String initMethod;
private final String destroyMethod;
private Element postConstructMethod;
private Element preDestroyMethod;
private MethodReader initMethodReader;


MethodLifecycleReader(TypeElement type, String initMethod, String destroyMethod) {
MethodLifecycleReader(
TypeElement type, String initMethod, String destroyMethod, ImportTypeMap imports) {
this.initMethod = initMethod;
this.destroyMethod = destroyMethod;
for (Element element : type.getEnclosedElements()) {
ElementKind kind = element.getKind();
if (kind == ElementKind.METHOD) {
readMethod(element);
for (var element : ElementFilter.methodsIn(type.getEnclosedElements())) {
if (element.getSimpleName().toString().equals(initMethod)
|| AnnotationUtil.hasAnnotationWithName(element, "PostConstruct")) {
postConstructMethod = element;
this.initMethodReader= new MethodReader(element, type, imports);
}
if (element.getSimpleName().toString().equals(destroyMethod)
|| AnnotationUtil.hasAnnotationWithName(element, "PreDestroy")) {
preDestroyMethod = element;
}
}
}

private void readMethod(Element element) {
if (AnnotationUtil.hasAnnotationWithName(element, "PostConstruct")) {
postConstructMethod = element;
}
if (AnnotationUtil.hasAnnotationWithName(element, "PreDestroy")) {
preDestroyMethod = element;
}
}

String initMethod() {
return deriveFromBoth(initMethod, postConstructMethod);
}

MethodReader initMethodReader() {
return initMethodReader;
}

String destroyMethod() {
return deriveFromBoth(destroyMethod, preDestroyMethod);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ final class MethodReader {
private final boolean multiRegister;
private final BeanConditions conditions = new BeanConditions();
private MethodParam observeParameter;
private MethodReader initMethodReader;

MethodReader(ExecutableElement element, TypeElement beanType, ImportTypeMap importTypes) {
this(null, element, beanType, null, null, importTypes);
Expand Down Expand Up @@ -145,8 +146,10 @@ final class MethodReader {
new TypeReader(
beanTypes.orElse(List.of()), genericType, returnElement, importTypes, element);
typeReader.process();
MethodLifecycleReader lifecycleReader = new MethodLifecycleReader(returnElement, initMethod, destroyMethod);
MethodLifecycleReader lifecycleReader =
new MethodLifecycleReader(returnElement, initMethod, destroyMethod, importTypes);
this.initMethod = lifecycleReader.initMethod();
this.initMethodReader = lifecycleReader.initMethodReader();
this.destroyMethod = lifecycleReader.destroyMethod();
}
if (lazy && prototype) {
Expand Down Expand Up @@ -293,15 +296,47 @@ void builderAddBeanProvider(Append writer) {
}

startTry(writer, " ");
writer.indent(indent).append(" return ");
writer.append("factory.%s(", methodName);

writer.indent(indent).append(" var $bean = factory.%s(", methodName);
for (int i = 0; i < params.size(); i++) {
if (i > 0) {
writer.append(", ");
}
params.get(i).builderGetDependency(writer, "builder");
}
writer.append(");").eol();
//
if (notEmpty(initMethod)) {
writer.indent(indent).append(" $bean.%s(", initMethod);
initMethodReader.read();
BeanReader.writeLifeCycleGet(
writer,
initMethodReader.params(),
"builder",
"builder.get(io.avaje.inject.BeanScope.class)");

writer.append(";").eol();
}
final var isCloseable = typeReader != null && typeReader.isClosable();

var priority = priority(destroyPriority);
if (notEmpty(destroyMethod)) {
writer.indent(indent).append("builder.addPreDestroy(%s%s);", addPreDestroy(destroyMethod), priority).eol();
} else if (isCloseable && !priority.isBlank()) {
writer.indent(indent).append("builder.addPreDestroy($bean::close%s);", priority).eol();
} else if (isCloseable || beanCloseable) {
writer.indent(indent).append("builder.addAutoClosable($bean);").eol();
}

var matchedPreDestroyMethod = factory.matchPreDestroy(returnTypeRaw);
if (matchedPreDestroyMethod != null) {
// PreDestroy method on the factory
var methodPriority = priority(matchedPreDestroyMethod.priority());
var method = String.format("() -> factory.%s($bean)", matchedPreDestroyMethod.method());
writer.indent(indent).append("builder.addPreDestroy(%s%s);", method, methodPriority).eol();
}
//
writer.indent(indent).append(" return $bean;").eol();
endTry(writer, " ");
writer.indent(indent);
if (proxyLazy) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ private void writeAddFor(MethodReader constructor) {
writeExtraInjection();
}
if (beanReader.registerProvider()) {
beanReader.prototypePostConstruct(writer, indent);
beanReader.providerLifeCycle(writer, indent);
writer.indent(" return bean;").eol();
if (!constructor.methodThrows()) {
writer.append(" }");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import java.io.IOException;

import io.avaje.inject.BeanScope;
import io.avaje.inject.Lazy;
import io.avaje.inject.PostConstruct;
import io.avaje.inject.PreDestroy;
import io.avaje.inject.Primary;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
Expand All @@ -20,6 +23,12 @@ public LazyBean(Provider<Integer> intProvider) {
this.intProvider = intProvider;
}

@PostConstruct
void init(BeanScope scope) {}

@PreDestroy
void shutdown() {}

public LazyBean() {}

void something() throws IOException {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import io.avaje.inject.Factory;
import io.avaje.inject.Lazy;
import io.avaje.inject.Primary;
import jakarta.inject.Named;

@Lazy
@Factory
Expand All @@ -19,4 +20,11 @@ Integer lazyInt() {
LazyInterface lazyInterface() {
return null;
}


@Bean
@Named("other")
LazyBean lazy2() {
return null;
}
}
Loading