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()));
Related
Function to be tested:
public void deleteFile(File file) {
try {
Files.delete(file.toPath()) ;
log.info("Csv file deleted from system succesfully after processing the data");
} catch (IOException e) {
// TODO Auto-generated catch block
}
}
Test code:
#Test
void testExceptionDuringDeletingFile() {
helper=mock(Helper.class);
//String bucket ="bucket";
//String key = "key";
File file = new File("");
doThrow(IOException.class).when(helper).deleteFile(file);
Assertions.assertThrows(IOException.class,()->helper.deleteFile(file));
}
But I am getting the following exception:
org.mockito.exceptions.base.MockitoException: Checked exception is
invalid for this method! Invalid: java.io.IOException at
com.lululemon.product.ap.reprocess.producer.HelperTests.testExceptionDuringDeletingFile(HelperTests.java:191)
at
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native
Method) at
Because your deleteFile() method doesn't throw the IOException. You catch it in your method implementation and do something with it.
And, your mocked Helper class instance really can't throw IOException from the deleteFile() method because the real deleteFile() method doesn't.
Throw the IOException from your method and you won't get the error.
deleteFile method:
public void deleteFile(File file) throws IOException {
try {
Files.delete(file.toPath());
log.info("Csv file deleted from system successfully after processing the data");
} catch (IOException e) {
throw new IOException("Couldn't delete file. Try again!");
}
}
Test method:
#Test
void testExceptionDuringDeletingFile() throws IOException {
File file = new File("");
Helper helper = mock(Helper.class);
doThrow(IOException.class).when(helper).deleteFile(file);
Assertions.assertThrows(IOException.class, () -> helper.deleteFile(file));
}
Is there any support for handling custom exception inside the Collectors.toMap.
I am calling a method inside the Collector.toMap which throws MyException. Can it be rethrown in the calling function pupulateValues()? For demonstration I used below code to rethrow MyException but couldn't get through. My objective is to handle MyException in main method.
public static void main(String[] args){
try {
pupulateValues();
} catch (MyException e) {
// do something
e.printStackTrace();
}
}
private static void pupulateValues() throws MyException{
Map<String,String> map = new HashMap<>();
map.put("asdf", "asdf");
map.put("ss", "fff");
map.put("aaaaaa", "aaaaaaa");
Map<String,String> map2=map.entrySet().stream().collect(
Collectors.toMap(entry->entry.getKey(),entry-> {
try {
return getCert(entry.getValue());
} catch (MyException e) {
// TODO Auto-generated catch block
throw new MyException();
}}));
}
static String getCert(String val) throws MyException {
if(val == null) {
throw new MyException("Some exception");
}
return val;
}
You have a few options:
make MyException an unchecked exception
wrap it: catch (MyException e) { throw new RuntimeException(e); }
trick the compiler:
https://stackoverflow.com/a/19757456/829571
https://stackoverflow.com/a/31470959/829571
https://github.com/jOOQ/jOOL#orgjooqlambdaunchecked
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();
}
}
We are having some issue with XML file generation using JAXB.(The generated file is corrupted/jumbled even if we validate against XSD). But no errors are reported in server logs(catalina.out)
While we were doing the investigations, we happened to found the following code segment in com.sun.xml.internal.bind.v2.runtime.MarshallerImpl(This is the runtime class used by java to marshall the JAXB objects to XML).
/**
* All the marshal method invocation eventually comes down to this call.
*/
private void write(Object obj, XmlOutput out, Runnable postInitAction) throws JAXBException {
try {
if( obj == null )
throw new IllegalArgumentException(Messages.NOT_MARSHALLABLE.format());
if( schema!=null ) {
// send the output to the validator as well
ValidatorHandler validator = schema.newValidatorHandler();
validator.setErrorHandler(new FatalAdapter(serializer));
// work around a bug in JAXP validator in Tiger
XMLFilterImpl f = new XMLFilterImpl() {
#Override
public void startPrefixMapping(String prefix, String uri) throws SAXException {
super.startPrefixMapping(prefix.intern(), uri.intern());
}
};
f.setContentHandler(validator);
out = new ForkXmlOutput( new SAXOutput(f) {
#Override
public void startDocument(XMLSerializer serializer, boolean fragment, int[] nsUriIndex2prefixIndex, NamespaceContextImpl nsContext) throws SAXException, IOException, XMLStreamException {
super.startDocument(serializer, false, nsUriIndex2prefixIndex, nsContext);
}
#Override
public void endDocument(boolean fragment) throws SAXException, IOException, XMLStreamException {
super.endDocument(false);
}
}, out );
}
try {
prewrite(out,isFragment(),postInitAction);
serializer.childAsRoot(obj);
postwrite();
} catch( SAXException e ) {
throw new MarshalException(e);
} catch (IOException e) {
throw new MarshalException(e);
} catch (XMLStreamException e) {
throw new MarshalException(e);
} finally {
serializer.close();
}
} finally {
cleanUp();
}
}
private void cleanUp() {
if(toBeFlushed!=null)
try {
toBeFlushed.flush();
} catch (IOException e) {
// ignore
}
if(toBeClosed!=null)
try {
toBeClosed.close();
} catch (IOException e) {
// ignore
}
toBeFlushed = null;
toBeClosed = null;
}
The method write(Object obj, XmlOutput out, Runnable postInitAction) calls the cleanup method in the finally clause and there is the flushing is happening. But in this cleanup method while flushing if any IOException happens, they ignore the exception.
We are wondering, whether this segments generated the corrupted XML as it does not throw back the exception and simply eats up the exception.
Also we have found the following statement in API documentation of XML serializer.
class: org.apache.xml.serialize.XMLSerializer
If an I/O exception occurs while serializing, the serializer will not throw an exception directly, but only throw it at the end of serializing (either DOM or SAX's DocumentHandler.endDocument().
Any help is appreciated.
Regards,
Mayuran
The IOException is not being ignore its being wrapped in a MarshalException and re thrown. The underlying issue should be present in the MarshalException you are receiving.
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.