How to use guava Closer properly - java

i'm struggling to figure out how to use the Closer utility from the guava library. Please see the code below.
One thing is, that the IndexWriter throws an IOException on both object initialization and close(). Therefore, the code in the finally and rethrow blocks is underlined.
The other question is, why do i have to catch Throwable instead of other exception types and do i have to rethrow the errors (i would prefer to log those at the spot)
`
int getDocumentsCount() {
Closer closer = Closer.create();
try {
IndexWriter iwriter = closer.register(openIndexWriter());
return iwriter.numDocs();
} catch (Throwable e) {
logger.error(e, e);
return -1;
} finally {
closer.close();
}
}
IndexWriter openIndexWriter() throws IOException {
return new IndexWriter(directory, analyzer, false,
IndexWriter.MaxFieldLength.UNLIMITED);
}
`
Thanks a lot
(stuck with Java 6)

From Guava's own explanation, you have to use Throwable, yes.
Here's their example snippet:
public void foo() throws IOException {
Closer closer = Closer.create();
try {
InputStream in = closer.register(openInputStream());
OutputStream out = closer.register(openOutputStream());
// do stuff with in and out
} catch (Throwable e) { // must catch Throwable
throw closer.rethrow(e);
} finally {
closer.close();
}
}
Note that they catch Throwable and rethrow it directly from the Closer instance.
As to why it is Throwable and not, let's say IOException or RuntimeException, it's because the Closer must know that an error occurred so that it can close the resources properly. All is only a matter of doing things proper. So it can work if you don't do it properly, but it's not guaranteed.
Not that if your method can throw MyOwnCheckedException, for instance, you have to declare them:
} catch (Throwable t) {
throw closer.rethrow(e, MyOwnCheckedException.class);
} finally {
closer.close();
}
Java 7 example, for comparison:
public void foo() throws IOException {
try (InputStream in = openInputStream();
OutputStream out = openOutputStream();
// do stuff with in and out
}
}
If you compare the Closer example with the Java 7 example, you can see that I still have to declare the IOException in the method signature.
For your case, this is what you have to do:
int getDocumentsCount() {
try {
Closer closer = Closer.create();
try {
IndexWriter iwriter = closer.register(openIndexWriter());
return iwriter.numDocs();
} catch (Throwable e) {
closer.rethrow(e);
} finally {
closer.close();
}
} catch (IOException e) {
logger.error(e, e);
return -1;
}
}
To avoid try-pyramids, I'd do the following:
int getDocumentsCount() {
try {
return doGetDocumentsCount();
} catch (IOException e) {
logger.error(e, e);
return -1;
}
}
int doGetDocumentsCount() throws IOException {
Closer closer = Closer.create();
try {
IndexWriter iwriter = closer.register(openIndexWriter());
return iwriter.numDocs();
} catch (Throwable e) {
closer.rethrow(e);
} finally {
closer.close();
}
}

Related

How to use Suppliers.memoize when method throws Checked-Exception

I'm trying to use Suppliers#memorize on a function that throws IOException
Snippet:
private Supplier<Map> m_config = Suppliers.memoize(this:toConfiguration);
This gives an exception:
Unhandled exception type IOException
so I had to do something like this:
public ClassConstructor() throws IOException
{
m_config = Suppliers.memoize(() -> {
try
{
return toConfiguration(getInputFileName()));
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
});
if(m_Configuration == null) {
throw new IOException("Failed to handle configuration");
}
}
I would like the CTOR to forward the IOException to the caller.
The proposed solution is not so clean, is there a better way to handle this situation?
Use UncheckedIOException
You're tagging java-8, so you should use the UncheckedIOException which is present for this very use case.
/**
* #throws java.io.UncheckedIOException if an IOException occurred.
*/
Configuration toConfiguration(String fileName) {
try {
// read configuration
} catch (IOException e) {
throw new java.io.UncheckedIOException(e);
}
}
Then, you can write:
m_config = Suppliers.memoize(() -> toConfiguration(getInputFileName()));

How to handle exceptions you want propagated up to the caller?

I'm a Pythonista moving into Java/Scala, and I am wondering how to handle the case where you want an exception to be thrown if it occurs. Take the following toy example:
public class PersonSaver {
private final File file;
public PersonSaver(File file) {
this.file = file;
}
public void save(List<Person> people) {
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
In Python I would want this to throw an error if the file isn't found, and let the calling code handle the exception. Is it convention just to re-throw the same exception?
You can make your method throw those exceptions :
public class PersonSaver {
private final File file;
public PersonSaver(File file) {
this.file = file;
}
public void save(List<Person> people) throws FileNotFoundException {
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
} catch (IOException e) {
//handle the exception you want to handle
e.printStackTrace();
}
}
}
Just make sure you declare your method with the throws statement, or your compiler might not like it ;)
You can also go this way (let's call this a semi-exception-handling) :
public class PersonSaver {
private final File file;
public PersonSaver(File file) {
this.file = file;
}
public void save(List<Person> people) throws FileNotFoundException, IOException {
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
} catch (IOException e) {
/*Some code to clear some data or to handle the
exception but still throw an exception higher*/
throw e;
}
}
}
You can just do the following...
public class PersonSaver {
private final File file;
public PersonSaver(File file) {
this.file = file;
}
public void save(List<Person> people) throws FileNotFoundException {
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
} catch (IOException e) {
e.printStackTrace();
}
}
}
In any part of your code you can throw a throwable object, such as an Exception.
You should also state it in the method signature, letting the JVM know you'll handle that Exception in a caller's block.
Example:
public void save(List<Person> people) throws FileNotFoundException{
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
} catch (IOException e) {
e.printStackTrace();
}
}
You need to consider if the calling code actually knows what to do with the specific exception. You have defined an API about saving a collection of Person. The calling code knows only about a Person and has no idea ideally where the save is done.
If you throw a lower level exception about the file not found you are leaking the abstraction and you won't be able to change the implementation easily if the calling code is starting to be aware of where things are saved.
The proper approach would be to throw an "business" exception like PersonNotPersisted or PersonNotSaved since this is something the calling code would understand and avoid the low level IO exceptions to the higher layer
If you declare a method to throws an checkedexception you dont need to catch it or any of it subtypes:
public void save(List<Person> people) throws IOExcetion {
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
}
}
If you want to handle the exception before you can also do like:
public void save(List<Person> people) throws IOException {
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
} catch (IOException e) {
e.printStackTrace();
throw e;
}
}
The keyword 'throw' fires the exception to the caller.

Copy (over a web API) is complete; I get a broken pipe anyway. How to solve it?

For one of my projects, I implement a Java 7 FileSystem over the Box API Java SDK (the new one).
However, for downloading files, when you want to have a stream to the content, it only provides methods taking OutputStream as an argument; specifically, I am using this one at the moment.
But this doesn't sit well with the JDK API; I need to be able to implement FileSystemProvider#newInputStream()... Therefore I elected to use Pipe{Input,Output}Stream.
Moreover, since the Box SDK API methods are synchronous (not that it matters here), I wrap them in a Future. My code is as follows (imports ommitted for brevity):
#ParametersAreNonnullByDefault
public final class BoxFileInputStream
extends InputStream
{
private final Future<Void> future;
private final PipedInputStream in;
public BoxFileInputStream(final ExecutorService executor,
final BoxFile file)
{
in = new PipedInputStream(16384);
future = executor.submit(new Callable<Void>()
{
#Override
public Void call()
throws IOException
{
try {
file.download(new PipedOutputStream(in));
return null;
} catch (BoxAPIException e) {
throw BoxIOException.wrap(e);
}
}
});
}
#Override
public int read()
throws IOException
{
try {
return in.read();
} catch (IOException e) {
future.cancel(true);
throw new BoxIOException("download failure", e);
}
}
#Override
public int read(final byte[] b)
throws IOException
{
try {
return in.read(b);
} catch (IOException e) {
future.cancel(true);
throw new BoxIOException("download failure", e);
}
}
#Override
public int read(final byte[] b, final int off, final int len)
throws IOException
{
try {
return in.read(b, off, len);
} catch (IOException e) {
future.cancel(true);
throw new BoxIOException("download failure", e);
}
}
#Override
public long skip(final long n)
throws IOException
{
try {
return in.skip(n);
} catch (IOException e) {
future.cancel(true);
throw new BoxIOException("download failure", e);
}
}
#Override
public int available()
throws IOException
{
try {
return in.available();
} catch (IOException e) {
future.cancel(true);
throw new BoxIOException("download failure", e);
}
}
#Override
public void close()
throws IOException
{
IOException streamException = null;
IOException futureException = null;
try {
in.close();
} catch (IOException e) {
streamException = e;
}
try {
future.get(5L, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
futureException = new BoxIOException("donwload interrupted", e);
} catch (ExecutionException e) {
futureException = new BoxIOException("download failure",
e.getCause());
} catch (CancellationException e) {
futureException = new BoxIOException("download cancelled", e);
} catch (TimeoutException e) {
futureException = new BoxIOException("download timeout", e);
}
if (futureException != null) {
if (streamException != null)
futureException.addSuppressed(streamException);
throw futureException;
}
if (streamException != null)
throw streamException;
}
#Override
public synchronized void mark(final int readlimit)
{
in.mark(readlimit);
}
#Override
public synchronized void reset()
throws IOException
{
try {
in.reset();
} catch (IOException e) {
future.cancel(true);
throw new BoxIOException("download failure", e);
}
}
#Override
public boolean markSupported()
{
return in.markSupported();
}
}
The code consistenly fails with the following stack trace (that is in int read(byte[]):
Exception in thread "main" com.github.fge.filesystem.box.exceptions.BoxIOException: download failure
at com.github.fge.filesystem.box.io.BoxFileInputStream.read(BoxFileInputStream.java:81)
at java.nio.file.Files.copy(Files.java:2735)
at java.nio.file.Files.copy(Files.java:2854)
at java.nio.file.CopyMoveHelper.copyToForeignTarget(CopyMoveHelper.java:126)
at java.nio.file.Files.copy(Files.java:1230)
at Main.main(Main.java:37)
[ IDEA specific stack trace elements follow -- irrelevant]
Caused by: java.io.IOException: Pipe broken
at java.io.PipedInputStream.read(PipedInputStream.java:322)
at java.io.PipedInputStream.read(PipedInputStream.java:378)
at java.io.InputStream.read(InputStream.java:101)
at com.github.fge.filesystem.box.io.BoxFileInputStream.read(BoxFileInputStream.java:78)
... 10 more
But when it fails, the download is already complete...
OK, the thing is, I can grab the file size and hack around it but I'd prefer not to if at all possible; how can I modify this code so as to avoid EPIPE?
The SDK also provides BoxAPIRequest and BoxAPIResponse classes that let you make manual requests for advanced use-cases. These classes still automatically handle authentication, errors, back-off, etc. but give you more granular control over the request.
In your case, you could do make a download request manually by doing:
// Note: this example assumes you already have a BoxAPIConnection.
URL url = new URL("files/" + file.getID() + "/content")
BoxAPIRequest request = new BoxAPIRequest(api, url, "GET");
BoxAPIResponse response = request.send();
InputStream bodyStream = response.getBody();
// Use the stream.
response.disconnect();
Well, I found the solution, although I am not very satisfied with it...
Since I can know the file size which I try to open an inputstream on, I just pick the size and decrease it by the amount of bytes read -- unless the size reaches 0, in this case all read methods return -1.

How to specify a message on a method "throws" in Java?

Im trying to return a JOptionePane message dialog for each one of the possible throws on my method:
public void add_note(String note) throws FileNotFoundException, IOException, InvalidFormatException{
... content ...
}
Is there any way to do this?
You could try something like :
public void add_note(String note) throws FileNotFoundException, IOException, InvalidFormatException
{
try
{
...content...
}
catch(FileNotFoundException fnfEx)
{
throw new FileNotFoundException("File was not found");
}
catch(IOException ioEx)
{
throw new FileNotFoundException("I/O exception");
}
catch(InvalidFormatException invEx)
{
throw new FileNotFoundException("Invalid format errror");
}
}
Where you put the message you want in the new exceptions and you print the exception message in the JOptionPane.
wrap your code inside try catch. Inside catch block for each exception type throw the message specific to each exception
Using a Try-Catch you can catch any exception and return something when an exception occurs. You should do this for all of your cases.
public void add_note(String note){
try {
//code
} catch (FileNotFoundException e) {
//return something
}
}
Instead of throwing exceptions, handle each individually in your method:
public JOptionPane add_note(String note) {
try {
...
} catch (FileNotFoundException fnfe) {
return ...;
} catch (IOException ioe) {
return ...;
} catch (InvalidFormatException ife) {
return ...;
}
}
I'll suggest you an alternative approach, as no one mentioned it.
I'd use AOP to catch those exceptions and show to the end user. You'll write a simple aspect, and dont mess your code with try and catch blocks.
Here is an example of such aspect
#Aspect
public class ErrorInterceptor{
#AfterThrowing(pointcut = "execution(* com.mycompany.package..* (..))", throwing = "exception")
public void errorInterceptor(Exception exception) {
if (logger.isDebugEnabled()) {
logger.debug("Error Message Interceptor started");
}
// DO SOMETHING HERE WITH EXCEPTION
logger.debug( exception.getCause().getMessage());
if (logger.isDebugEnabled()) {
logger.debug("Error Message Interceptor finished.");
}
}
}
If you don't know what Aspect Oriented Programming is definitely go check it out, this is very powerfull concept (just like OOP), spend some time to learn it.
If you want to show a dialog with the JOptionPane.showMessageDialog do as follows:
public void add_note(String note){
try {
//code
} catch (FileNotFoundException | IOException | InvalidFormatException e) {
JOptionPane.showMessageDialog(frame, e.getMessage(), "Title", JOptionPane.ERROR_MESSAGE);
//manage the exception here
}
}

DRY for Exception Wrapping

I'm working on some server-side code that wraps all exceptions before passing them to the client side, due to this all client facing methods have the following code
try{
DoSomething();
} catch (ExceptionA e) {
throw new CustomException(AType, e);
} catch (ExceptionB e) {
throw new CustomException(BType, e);
} catch (Exception e) {
throw new CustomException(Unexpected, e);
}
to have this repeated in every method seems to violate the DRY principle and I was wondering what the best way to refactor it would be. For instance I was thinking a wrapper method such as:
private void wrapException(Exception e) {
if (e instanceof ExceptionA) {
throw new CustomException(AType, e);
}
etc...
Take a look at AspectJ soften exception.
Also look at Guava's Throwables.
There is also Lamboks sneaky exception.
The other option is to use Anonymous object instances aka closures.
public abstract class Wrapper {
public void execute() {
try {
// do some boiler plate before
this.wrap();
// do some boiler plate after.
} catch (ExceptionA | ExceptionB ex) {
Type t = determineType(ex);
throw new CustomException(t, ex);
}
}
public void abstract wrap();
}
Now in your code you do something like:
new Wrapper() {
public void wrap() {
DoSomething();
}
}.execute()
This is possible in Java7 and up:
http://docs.oracle.com/javase/7/docs/technotes/guides/language/catch-multiple.html
Copy-paste example from above doc:
catch (IOException|SQLException ex) {
logger.log(ex);
throw ex;
}
This is one way to go about it:
Exception caughtEx = null;
String extraInfo = null;
try{
DoSomething();
} catch (ExceptionA e) {
caughtEx = e;
extraInfo = AType;
} catch (ExceptionB e) {
caughtEx = e;
extraInfo = BType;
} catch (Exception e) { // catching Exception is usually a bad idea, just let it bubble up without catching...
caughtEx = e;
extraInfo = Unexpected;
}
if (caughtEx != null) throw new CustomException(extraInfo, caughtEx);

Categories

Resources