Wrapping BodySubscriber<InputStream> in GZIPInputStream leads to hang - java

I'm using the new java.net.http classes to handle asynchronous HTTP request+response exchanges, and I'm trying to find a way to have the BodySubscriber handle different encoding types such as gzip.
However, mapping a BodySubsriber<InputStream> so that the underlying stream is wrapped by a GZIPInputStream (when "Content-Encoding: gzip" is found in the response header) leads to a hang. No exceptions, just a total cessation of activity.
The code which maps the BodySubscriber looks like this:
private HttpResponse.BodySubscriber<InputStream> gzippedBodySubscriber(
HttpResponse.ResponseInfo responseInfo) {
return HttpResponse.BodySubscribers.mapping(
HttpResponse.BodySubscribers.ofInputStream(),
this::decodeGzipStream);
}
private InputStream decodeGzipStream(InputStream gzippedStream) {
System.out.println("Entered decodeGzipStream method.");
try {
InputStream decodedStream = new GZIPInputStream(gzippedStream);
System.out.println(
"Created GZIPInputStream to handle response body stream.");
return decodedStream;
} catch (IOException ex) {
System.out.println("IOException occurred while trying to create GZIPInputStream.");
throw new UncheckedIOException(ex);
}
}
Receiving an HTTP response which has "gzip" encoding leads to the console showing just this:
Entered EncodedBodyHandler.apply method.
Entered decodeGzipStream method.
Nothing more is seen, so the line after the call to the GZIPInputStream constructor is never executed.
Does anyone know why this attempt to wrap the InputStream from a BodySubscriber<InputStream> in a GZIPInputStream is hanging?
Note: the equivalent method for unencoded (raw text) HTTP response bodies contains simply a call to BodySubscribers.ofInputStream() with no mapping, and this allows the response to be received and displayed without problem.

EDIT: JDK-8217264 is fixed since JDK13
This is indeed a bug. I have logged JDK-8217264. I can suggest two work-arounds:
Workaround one
Do not use BodySubscribers.mapping - but transform the InputStream into a GZIPInputStream after getting the HttpResponse's body:
GZIPInputStream gzin = new GZIPInputStream(resp.getBody());
Workaround two
Have the mapping function return a Supplier<InputStream> instead, taking care not to create the GZIPInputStream until Supplier::get is called
static final class ISS implements Supplier<InputStream> {
final InputStream in;
GZIPInputStream gz;
ISS(InputStream in) {
this.in = in;
}
public synchronized InputStream get() {
if (gz == null) {
try {
gz = new GZIPInputStream(in);
} catch (IOException t) {
throw new UncheckedIOException(t);
}
}
return gz;
}
}

Encountered the exact same problem. I tried the example in the Javadoc of the BodySubscribers.mapping method. Same behavior, the application hangs without any errors.
Could be a bug, because this is an official example from the Javadoc.
public static <W> BodySubscriber<W> asJSON(Class<W> targetType) {
BodySubscriber<InputStream> upstream = BodySubscribers.ofInputStream();
BodySubscriber<W> downstream = BodySubscribers.mapping(
upstream,
(InputStream is) -> {
try (InputStream stream = is) {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(stream, targetType);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});
return downstream;
} }

Related

How to upload zip file through REST API Mule 4?

I'm trying to upload zip file to the url https://anypoint.mulesoft.com/designcenter/api-designer/projects/{projectId}/branches/master/import. Content-Type must be application/zip, cant change to multipart/form-data. In Mule 3, a java transform class is used (com.test.FileReader) with the FileReader.class is stored in lib. It worked in Mule 3.
I tried to use ReadFile component to read test.zip and set as payload but it's not working. Any suggestion how to upload zip file in Mule 4?
package com.test;
import org.mule.transformer.*;
import org.mule.api.*;
import org.mule.api.transformer.*;
import java.io.*;
public class PayloadFileReader extends AbstractMessageTransformer
{
public Object transformMessage(final MuleMessage message, final String outputEncoding) throws TransformerException {
byte[] result = null;
try {
result = this.readZipFile("test.zip");
}
catch (Exception e) {
e.printStackTrace();
}
message.setPayload((Object)result);
return message;
}
public String readFileTest(final String path) throws FileNotFoundException, IOException, Exception {
final ClassLoader classLoader = this.getClass().getClassLoader();
final File file = new File(classLoader.getResource(path).getFile());
final FileReader fileReader = new FileReader(file);
BufferedReader bufferReader = null;
final StringBuilder stringBuffer = new StringBuilder();
try {
bufferReader = new BufferedReader(fileReader);
String line;
while ((line = bufferReader.readLine()) != null) {
stringBuffer.append(line);
}
}
catch (IOException e) {
e.printStackTrace();
if (bufferReader != null) {
try {
bufferReader.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
finally {
if (bufferReader != null) {
try {
bufferReader.close();
}
catch (IOException e2) {
e2.printStackTrace();
}
}
}
return stringBuffer.toString();
}
public byte[] readZipFile(final String path) {
final ClassLoader classLoader = this.getClass().getClassLoader();
final File file = new File(classLoader.getResource(path).getFile());
final byte[] b = new byte[(int)file.length()];
try {
final FileInputStream fileInputStream = new FileInputStream(file);
fileInputStream.read(b);
fileInputStream.close();
}
catch (FileNotFoundException e) {
System.out.println("Not Found.");
e.printStackTrace();
}
catch (IOException e2) {
System.out.println("Error");
e2.printStackTrace();
}
return b;
}
}
'
Assuming that your zip file corresponds to a valid API spec, in Mule 4, you don't need to use a custom java code to achieve what you want: you can read the file content using the File connector Read operation, and use an HTTP Request to upload it to Design Center using Design Center API. Your flow should look like:
For the Read operation, you only need to set the file location, in the File Path operation property.
No need to set content type in the HTTP Request (Mule 4 will configure the content type automatically based on the file content loaded by the Read operation).
You can't use Java code that depends on Mule 3 classes in Mule 4. Don't bother trying to adapt the code, it is not meant to work. Their architecture are just different.
While in Mule 4 you can use plain Java code or create a module with the SDK, there is no reason to do so for this problem and it would be counterproductive. My advise it to forget the Java code and resolve the problem with pure Mule 4 components.
In this case there doesn't seem a need to actually use Java code. The File connector read operation should read the file just fine as it doesn't appear the Java code is doing anything else than reading the file into the payload.
Sending through the HTTP Request connector should be straightforward. You didn't provide any details of the error, (where is it happening, complete error message, HTTP status error code, complete flow with the HTTP request in both versions, etc) and the API Designer REST API doesn't document an import endpoint so it is difficult to say if the request is correctly constructed.

Java: Why does an unclosed stream not throw an exception?

I wanted to write to a property file. But it silently never worked. Just from the code behavior I could not notice it. I always had to open the properties file and look if the value changed. But it never did. So actually I would expect to get an exception . The problem seemed to be that I did not close the InputStream before opening the OutputStream. But I never got to know that. It cost me 3 days because I would expect either OutputStream or store function to give me some feedback. Have a look at the code.
File file = ResourceUtils.getFile("classpath:First.properties");
FileInputStream in = new FileInputStream(file);
Properties props = new Properties();
props.load(in);
System.out.println(props.getProperty("country"));
in.close(); // This I always forgot
FileOutputStream out = new FileOutputStream(file);
props.setProperty("country", "germany");
props.store(out, null);
System.out.println(props.getProperty("country"));
out.close();
As for the actual question "why does it not throw an exception", it's because there are cases you want the Stream to remain open.
class FileWriteSample implements Closeable {
FileOutputStream writeTo;
public FileWriteSample(String filename) throws IOException {
writeTo = new FileOutputStream(filename);
// should we expect an Exception here because we don't close the Stream?
// we're planning to use it later on
}
public void write(String s) {
// write to stream
}
public void close() throws IOException {
writeTo.close();
}
}
A forgotten close() statement cannot cause an exception. From the perspective of your stream everything is okay. It just didn't wrote to its destination yet. Why should it? Even when the whole program terminates there is no guaranty that the stream closes and writes its internal buffers out.[1]
You always have to call flush() or close() actively. The underlying implementation will then perform the actual write operation.
This mistake is so common that there is an extra Java-Feature to handle it. It is called try-with-resources and prevents programmers from the evil consequences of missing close() statements.
Example:
//use try-with-resources on out
private void saveProperties(Properties properties, String path) {
try(PrintStream out = new PrintStream(new FileOutputStream(path))) {
printProperties(properties,out);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// you can pass System.out as well to print to console
private void printProperties(Properties properties, PrintStream out) {
try {
properties.store(out, null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//properties.load leaves the stream open, so you have to use try-with-resources
private Properties readProperties(String path) {
try (FileInputStream in = new FileInputStream(path)) {
Properties properties = new Properties();
properties.load(in);
return properties;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Related posts on Java Properties:
Read properties from outside of a jar: https://stackoverflow.com/a/54766296/1485527
Sorted print of properties: https://stackoverflow.com/a/54781548/1485527
Related posts on Java Streams:
Closing Streams in Java
[1] See: Josh Bloch, Effective Java,(2nd ed.), Page 27.
Avoid finalizers.[...] It is entirely possible, even likely, that a program terminates without executing finalizers on some objects that are no longer reachable.

converting a java.util.stream.Stream<String> into a java.io.Reader

Part of my application is given an InputStream and wants to do some processing on this to produce another InputStream.
try (
final BufferedReader inputReader = new BufferedReader(new InputStreamReader(inputStream, UTF_8), BUFFER_SIZE);
final Stream<String> resultLineStream = inputReader.lines().map(lineProcessor::processLine);
final InputStream resultStream = new ReaderInputStream(new StringStreamReader(resultLineStream), UTF_8);
) {
s3Client.putObject(targetBucket, s3File, resultStream, new ObjectMetadata());
} catch (IOException e) {
throw new RuntimeException("Exception", e);
}
I am using the new Java 8 BufferedReader.lines() to a Stream onto which I can easily map my processing function.
The only thing still lacking is class StringStreamReader() which is supposed to turn my Stream into a Reader from which Apache commons-io:ReaderInputStream can create an InputStream again. (The detour to readers and back seems reasonable to deal with encodings and line breaks.)
To be very clear, the code above assumes
public class StringStreamReader extends Reader {
public StringStreamReader(Stream<String> stringStream) { ... }
#Overwrite
public int read(char cbuf[], int off, int len) throws IOException { ... }
// possibly overwrite other methods to avoid bad performance or high resource-consumption
}
So is there any library that offers such a StringStreamReader class? Or this there another way to write the application code above without implementing a custom Reader or InputStream subclass?
You can do something like that:
PipedWriter writer = new PipedWriter();
PipedReader reader = new PipedReader();
reader.connect(writer);
strings.stream().forEach(string -> {
try {
writer.write(string);
writer.write("\n");
} catch (Exception e) {
e.printStackTrace();
}
});
But i guess you want some form of lazy processing. Stream api does not really help in that case, you need a dedicated Thread + some buffer to do that.

java.net.ProtocolException: Cannot write output after reading input

I am trying to send the object from applet to struts action class
using object output stream but it gives me a exception java.net.ProtocolException: Cannot write output after reading input.
I created a new instance of URLConnection to giving specific url
and tried to write object in url to send the struts action class from applet
i am calling this method on save button click of applet
public saveDesign()
{
try
{
HttpURLConnection urlConnection = getServletConnection(CallServletConnection.SAVE_DESIGN, null);
// Pragma = no-cache; should be null
if(urlConnection != null && urlConnection.getHeaderFields().get("Pragma") != null)
return false;
OutputStream outstream = urlConnection.getOutputStream();//Exception occur here
ObjectOutputStream objectoutstream = new ObjectOutputStream(outstream);
objectoutstream.writeObject("abc");
objectoutstream.flush();
objectoutstream.close();
System.out.println("vctObjectDetails is write ");
}
catch (MalformedURLException exception) {
exception.printStackTrace();
}
catch(ConnectException exception) {
exception.printStackTrace();
}
catch (IOException exception) {
exception.printStackTrace();
}
catch(Exception e)
{
e.printStackTrace();
}
}
but it doesn't work.
Please gives me some tips if anyone knows how to handle this exception.
It all has to do with the lifecycle of an HTTP request (which is what HttpURLConnection abstracts) - once the request has been sent, you cannot modify it any further - in case you have more data to send, you just make another one.
What is happening underneath is that once you call getHeaderFields() (the response header fields), the 'HttpURLConnection' sends the request and makes the response available.
I don't know what is in 'getServletConnection()', but you could try using 'doOutput()' and not reading from the response, until you have finished writing to the request.

Preferred way to clean-up resources in Java 1.6

I regularly see this style of resource clean-up:
InputStream in = null;
try {
in = new FileInputStream(file);
// ...
} finally {
if (in != null) {
in.close();
}
}
I have always used the following style:
final InputStream in = new FileInputStream(file);
try {
// ...
} finally {
in.close();
}
But am I missing something? Is there an advantage to the former that I'm not seeing?
I suspect its to avoid having two nested try/catch blocks instead of one.
InputStream in = null;
try {
in = new FileInputStream(file);
// ...
} catch(IOException ioe) {
// handle exception.
} finally {
IOUtils.closeQuietly(in);
}
The second case is incomplete.
try {
final InputStream in = new FileInputStream(file);
try {
// ...
} finally {
in.close();
}
} catch(IOException e) {
// handle exception
}
If you have multiple files, this could get really messy.
Suppose that in the first example you have some other code before defining in that gets you out of the try block. If you get to the finally without in been defined you will get a NullPointerException when trying to close it. So you will have to make the check to avoid errors like that.
This is very simple example, And may not create a problem as you are creating InputStream in same bloke. But if InputStream is closed because of some Exception or other fault, in that case your code will fail, So its always better to check if InputStream is available
The second one will not compile since the constructor of FileInputStream can throw a FileNotFoundException, thus you'd need an extra try-catch block, unless of course, the method itself throws it.
Another common idiom is to write a closeQuietly() method to avoid having to write the if (is != null) check all over your finally blocks. This is what Apache Common's IOUtils does:
public static void closeQuietly(InputStream input) {
try {
if (input != null) {
input.close();
}
} catch (IOException ioe) {
// ignore
}
}
Also note that since Java 7, you can use the following:
try (InputStream is = new FileInputStream(file)) {
} catch (final FileNotFoundException | IOException ex) {
}
The null check here for the InputStream is necessary as it is possible that the variable might not be assigned. In this case a NullPointerException would be thrown when attempting to close it when calling:
in.close();
In the 2nd block outside of the try/catch block:
final InputStream in = new FileInputStream(file);
try {
// ...
} finally {
in.close();
}
You can easily encounter other exceptions before entering the block and the InputStream is never closed.
Lets say you need to open not one, but two files. You would do
final InputStream in = new FileInputStream(file1);
final OutputStream out = new FileOutputStream(file2);
try {
// ...
} finally {
out.close();
in.close();
}
If the out fails to open, you will get an exception and because it's out of the try block in won't be closed in the finally block.
In the other method:
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(file1);
out = new FileOutputStream(file2);
// ...
} finally {
if (out != null) out.close();
if (in != null) in.close();
}
If out fails to open, you will go to the finally block and close both streams. If in fails to open, you will go to the finally block, and free only in - because out==null.
edit
As the aetheria mentioned, that code wouldn't work because close() throws exception in Java. It can easily be fixed by putting each resource release in it's own try-catch block:
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(file1);
out = new FileOutputStream(file2);
// ...
} finally {
try{ out.close(); }catch(Exception e){}
try{ in.close(); }catch(Exception e){}
}
I ditched the null checking - if in or out is null, it'll throw a NullPointerException that will be ignored. And the reason I ignore close exceptions is that disposal methods shouldn't throw exceptions in the first place. If handling closing exceptions is required, you can always close the streams again, after the finally block. That way, any stream that can be closed will be closed already(so you wouldn't have to worry about it), and you can handle any exceptions from close more elegantly.
Now, aetheria also suggested to put a separate try-finally block for each resource that would look like this:
final InputStream in = new FileInputStream(file1);
try {
final OutputStream out = new FileOutputStream(file2);
try {
// ...
} finally {
out.close();
}
} finally {
in.close();
}
This works, but even with only two resources, it's much less elegant, as it splits the allocations and releasing code, making it harder to keep track of it(in my opinion, at least).

Categories