Skip to content

Commit fcc7be9

Browse files
committed
#117 - java.lang.AutoClosable automatically gets a PreDestroy hook
1 parent 965b45f commit fcc7be9

File tree

11 files changed

+101
-20
lines changed

11 files changed

+101
-20
lines changed

inject-generator/src/main/java/io/avaje/inject/generator/BeanReader.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ String getMetaKey() {
121121
* Return true if lifecycle via annotated methods is required.
122122
*/
123123
boolean hasLifecycleMethods() {
124-
return !requestScopedBean && (postConstructMethod != null || preDestroyMethod != null);
124+
return !requestScopedBean && (postConstructMethod != null || preDestroyMethod != null || typeReader.isClosable());
125125
}
126126

127127
List<MetaData> createFactoryMethodMeta() {
@@ -170,7 +170,7 @@ void addLifecycleCallbacks(Append writer) {
170170
if (preDestroyMethod != null) {
171171
writer.append(" builder.addPreDestroy($bean::%s);", preDestroyMethod.getSimpleName()).eol();
172172
} else if (typeReader.isClosable()) {
173-
writer.append(" builder.addPreDestroy(bean);").eol();
173+
writer.append(" builder.addPreDestroy($bean);").eol();
174174
}
175175
}
176176

inject-generator/src/main/java/io/avaje/inject/generator/Constants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
class Constants {
44

55
static final String IO_CLOSEABLE = "java.io.Closeable";
6+
static final String AUTO_CLOSEABLE = "java.lang.AutoCloseable";
67
static final String OPTIONAL = "java.util.Optional";
78
static final String KOTLIN_METADATA = "kotlin.Metadata";
89

inject-generator/src/main/java/io/avaje/inject/generator/MethodReader.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ void builderBuildAddBean(Append writer) {
143143
}
144144
if (notEmpty(destroyMethod)) {
145145
writer.append(indent).append("builder.addPreDestroy($bean::%s);", destroyMethod).eol();
146+
} else if (typeReader.isClosable()) {
147+
writer.append(indent).append("builder.addPreDestroy($bean::close);", destroyMethod).eol();
146148
}
147149
if (optionalType) {
148150
writer.append(" }").eol();
@@ -151,7 +153,7 @@ void builderBuildAddBean(Append writer) {
151153
}
152154

153155
private boolean hasLifecycleMethods() {
154-
return notEmpty(initMethod) || notEmpty(destroyMethod);
156+
return notEmpty(initMethod) || notEmpty(destroyMethod) || typeReader.isClosable();
155157
}
156158

157159
private boolean notEmpty(String value) {

inject-generator/src/main/java/io/avaje/inject/generator/TypeInterfaceReader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ void process() {
5050
String type = Util.unwrapProvider(anInterface.toString());
5151
if (type.indexOf('.') == -1) {
5252
context.logWarn("skip when no package on interface " + type);
53-
} else if (Constants.IO_CLOSEABLE.equals(type)) {
53+
} else if (Constants.AUTO_CLOSEABLE.equals(type) || Constants.IO_CLOSEABLE.equals(type)) {
5454
closeable = true;
5555
} else {
5656
final String iShortName = Util.shortName(type);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.example.closable;
2+
3+
import jakarta.inject.Singleton;
4+
5+
@Singleton
6+
public class ShouldCloseAuto2 implements AutoCloseable {
7+
8+
private boolean closed;
9+
10+
@Override
11+
public void close() throws Exception {
12+
closed = true;
13+
}
14+
15+
boolean isClosed() {
16+
return closed;
17+
}
18+
}

inject-test/src/test/java/org/example/closable/ShouldCloseAutoTest.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
class ShouldCloseAutoTest {
99

1010
@Test
11-
void test() {
11+
void test_closable() {
1212

1313
ShouldCloseAuto shouldCloseAuto;
1414
try (final BeanScope scope = BeanScope.newBuilder().build()) {
@@ -17,4 +17,15 @@ void test() {
1717

1818
assertThat(shouldCloseAuto.isClosed()).isTrue();
1919
}
20+
21+
@Test
22+
void test_autoCloseable() {
23+
24+
ShouldCloseAuto2 shouldCloseAuto;
25+
try (final BeanScope scope = BeanScope.newBuilder().build()) {
26+
shouldCloseAuto = scope.get(ShouldCloseAuto2.class);
27+
}
28+
29+
assertThat(shouldCloseAuto.isClosed()).isTrue();
30+
}
2031
}

inject-test/src/test/java/org/example/coffee/factory/MyFactory.java

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
import io.avaje.inject.Bean;
44
import io.avaje.inject.Factory;
5-
import org.example.coffee.factory.other.Something;
6-
75
import jakarta.inject.Named;
6+
import org.example.coffee.factory.other.Something;
87
import org.example.coffee.parent.DesEngi;
98

9+
import java.io.Closeable;
10+
import java.io.IOException;
11+
1012
@Factory
1113
public class MyFactory {
1214

@@ -53,7 +55,7 @@ void anotherCFact(CFact cfact) {
5355
@Named("BuildDesi1")
5456
DesEngi buildEngi() {
5557
methods += "|buildEngi1";
56-
return new DesEngi(){
58+
return new DesEngi() {
5759
@Override
5860
public String ignite() {
5961
return "buildEngi1";
@@ -68,6 +70,16 @@ DesEngi buildEngi2() {
6870
return new MyEngi();
6971
}
7072

73+
@Bean
74+
MyAutoClose buildAutoClose() {
75+
return new MyAutoClose();
76+
}
77+
78+
@Bean
79+
MyClose buildMyCloseable() {
80+
return new MyClose();
81+
}
82+
7183
String methodsCalled() {
7284
return methods;
7385
}
@@ -78,4 +90,32 @@ public String ignite() {
7890
return "MyEngi";
7991
}
8092
}
93+
94+
public static class MyAutoClose implements AutoCloseable {
95+
96+
boolean closed;
97+
98+
public boolean isClosed() {
99+
return closed;
100+
}
101+
102+
@Override
103+
public void close() throws Exception {
104+
closed = true;
105+
}
106+
}
107+
108+
public static class MyClose implements Closeable {
109+
110+
boolean closed;
111+
112+
public boolean isClosed() {
113+
return closed;
114+
}
115+
116+
@Override
117+
public void close() throws IOException {
118+
closed = true;
119+
}
120+
}
81121
}

inject-test/src/test/java/org/example/coffee/factory/MyFactoryTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,19 @@ public void methodsCalled() {
1717
}
1818
}
1919

20+
@Test
21+
public void closableBeans_expect_closedViaPreDestroy() {
22+
23+
final MyFactory.MyClose myClose;
24+
final MyFactory.MyAutoClose myAutoClose;
25+
try (BeanScope context = BeanScope.newBuilder().build()) {
26+
myClose = context.get(MyFactory.MyClose.class);
27+
myAutoClose = context.get(MyFactory.MyAutoClose.class);
28+
}
29+
assertThat(myClose.isClosed()).isTrue();
30+
assertThat(myAutoClose.isClosed()).isTrue();
31+
}
32+
2033
@Test
2134
public void factoryMethod_createsConcreteImplementation() {
2235
DesEngi buildDesi = ApplicationScope.get(DesEngi.class, "BuildDesi1");

inject/src/main/java/io/avaje/inject/spi/Builder.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import io.avaje.inject.RequestScopeProvider;
55
import jakarta.inject.Provider;
66

7-
import java.io.Closeable;
87
import java.util.List;
98
import java.util.Optional;
109
import java.util.Set;
@@ -93,7 +92,7 @@ static Builder newBuilder(List<SuppliedBean> suppliedBeans, List<EnrichBean> enr
9392
/**
9493
* Add lifecycle PreDestroy method.
9594
*/
96-
void addPreDestroy(Closeable closeable);
95+
void addPreDestroy(AutoCloseable closeable);
9796

9897
/**
9998
* Add field and method injection.

inject/src/main/java/io/avaje/inject/spi/DBeanScope.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
import org.slf4j.Logger;
55
import org.slf4j.LoggerFactory;
66

7-
import java.io.Closeable;
8-
import java.io.IOException;
97
import java.lang.annotation.Annotation;
108
import java.util.ArrayList;
119
import java.util.Collections;
@@ -21,14 +19,14 @@ class DBeanScope implements BeanScope {
2119

2220
private final ReentrantLock lock = new ReentrantLock();
2321
private final List<Runnable> postConstruct;
24-
private final List<Closeable> preDestroy;
22+
private final List<AutoCloseable> preDestroy;
2523
private final DBeanMap beans;
2624
private final Map<String, RequestScopeMatch<?>> reqScopeProviders;
2725
private final ShutdownHook shutdownHook;
2826
private boolean shutdown;
2927
private boolean closed;
3028

31-
DBeanScope(boolean withShutdownHook, List<Closeable> preDestroy, List<Runnable> postConstruct, DBeanMap beans, Map<String, RequestScopeMatch<?>> reqScopeProviders) {
29+
DBeanScope(boolean withShutdownHook, List<AutoCloseable> preDestroy, List<Runnable> postConstruct, DBeanMap beans, Map<String, RequestScopeMatch<?>> reqScopeProviders) {
3230
this.preDestroy = preDestroy;
3331
this.postConstruct = postConstruct;
3432
this.beans = beans;
@@ -131,10 +129,10 @@ public void close() {
131129
// we only allow one call to preDestroy
132130
closed = true;
133131
log.trace("firing preDestroy");
134-
for (Closeable closeable : preDestroy) {
132+
for (AutoCloseable closeable : preDestroy) {
135133
try {
136134
closeable.close();
137-
} catch (IOException e) {
135+
} catch (Exception e) {
138136
log.error("Error during PreDestroy lifecycle method", e);
139137
}
140138
}

inject/src/main/java/io/avaje/inject/spi/DBuilder.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package io.avaje.inject.spi;
22

3-
import io.avaje.inject.BeanScope;
43
import io.avaje.inject.BeanEntry;
4+
import io.avaje.inject.BeanScope;
55
import io.avaje.inject.RequestScopeMatch;
66
import io.avaje.inject.RequestScopeProvider;
77
import jakarta.inject.Provider;
88

9-
import java.io.Closeable;
109
import java.util.*;
1110
import java.util.function.Consumer;
1211

@@ -16,7 +15,7 @@ class DBuilder implements Builder {
1615
* List of Lifecycle methods.
1716
*/
1817
private final List<Runnable> postConstruct = new ArrayList<>();
19-
private final List<Closeable> preDestroy = new ArrayList<>();
18+
private final List<AutoCloseable> preDestroy = new ArrayList<>();
2019

2120
/**
2221
* List of field injection closures.
@@ -126,7 +125,7 @@ public void addPostConstruct(Runnable invoke) {
126125
}
127126

128127
@Override
129-
public void addPreDestroy(Closeable invoke) {
128+
public void addPreDestroy(AutoCloseable invoke) {
130129
preDestroy.add(invoke);
131130
}
132131

0 commit comments

Comments
 (0)