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

Add Closeables.closeable() to allow for wrapping non-Closeables for use with the try-with-resources statement #279

Open
lukaseder opened this issue Dec 30, 2016 · 5 comments

Comments

@lukaseder
Copy link
Member

Inspired by:
http://stackoverflow.com/q/41393417/521799

@bendem
Copy link

bendem commented Dec 30, 2016

So something like this?

try (Closeable<ExecutorService> closeableService = new Closeable<>(Executors.newSingleThreadExecutor(), ExecutorService::shutdown)) {
    ExecutorService service = closeableService.get();
    // ...
}
public class Closeable<Wrapped> extends AutoCloseable {

    private final Wrapped wrapped;
    private final CheckedRunnable cleanup;

    public Closeable(Wrapped wrapped, CheckedRunnable cleanup) {
        this.wrapped = wrapped;
        this.cleanup = cleanup;
    }

    public Wrapped get() { return wrapped; }

    @Override
    public void close() {
        try {
            cleanup.run();
        } catch (Throwable t) { // Some configurable error handling instead?
            throw new RuntimeException(t);
        }
    }
}

@lukaseder
Copy link
Member Author

Yes, in that direction, although, I wonder if we can create an intersection type <T & java.io.Closeable> (e.g. a Proxy) such that this get() method is not really needed...

@bendem
Copy link

bendem commented Dec 30, 2016

Ignoring the fact that we'd need to extract the interfaces to create the proxy, intersections seem to need both types to be concrete.

➜ java.py -s 'class A {
    static <T, R extends AutoCloseable & T> R a(Supplier<T> supplier, Consumer<T> cleanup) {
        System.out.println(supplier.getClass());
        return null;
    }
}' 'A.a(Executors::newSingleThreadExecutor, ExecutorService::shutdown)'
| /tmp/java.py/Paul19.java:34: error: unexpected type
|     static <T, R extends AutoCloseable & T> R a(Supplier<T> supplier, Consumer<T> cleanup) {
|                                          ^
|   required: class
|   found:    type parameter T
|   where T,R are type-variables:
|     T extends Object declared in method <T,R>a(Supplier<T>,Consumer<T>)
|     R extends AutoCloseable,T declared in method <T,R>a(Supplier<T>,Consumer<T>)
| 1 error
Compilation failed
➜ java.py -s 'class A {
    static <T, R extends T & AutoCloseable> R a(Supplier<T> supplier, Consumer<T> cleanup) {
        System.out.println(supplier.getClass());
        return null;
    }
}' 'A.a(Executors::newSingleThreadExecutor, ExecutorService::shutdown)'
| /tmp/java.py/Paul2.java:34: error: a type variable may not be followed by other bounds
|     static <T, R extends T & AutoCloseable> R a(Supplier<T> supplier, Consumer<T> cleanup) {
|                              ^
| 1 error
Compilation failed

@lukaseder
Copy link
Member Author

Indeed, also, they are not "denotable" types, i.e. the caller couldn't assign R and keep both T and Closeable semantics (at least not before var is introduced in Java 10).

@jdimeo
Copy link

jdimeo commented Feb 20, 2018

+1. Just needed this for Jersey responses:

@AllArgsConstructor(staticName = "wrap")
public class AutoCloseableResponse implements AutoCloseable {
	@Getter
	private Response response;
	
	@Override
	public void close() {
		response.close();
	}
}

Usage:

try  (val resp = AutoCloseableResponse.wrap(req.get())) {
   ...
}

(this is using Lombok)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants