inconsistent variable when passing it from one method to another - java

I have a problem that I have not been able to solve and it does not occur to me that it could be.
I have a class to which I am passing an InputStream from the main method, the problem is that when transforming the InputString to String with the class IOUtils.toString of AWS, or with the IOUtils of commons-io, they return
  an empty String
No matter what the problem may be, since inside the main class, it works correctly and returns the String it should, but when I use it inside the other class (without having done anything), it returns the empty String to me.
these are my classes:
public class Main {
public static void main(String [] args) throws IOException {
InputStream inputStream = new ByteArrayInputStream("{\"name\":\"Camilo\",\"functionName\":\"hello\"}".getBytes());
OutputStream outputStream = new ByteArrayOutputStream();
LambdaExecutor lambdaExecutor = new LambdaExecutor();
String test = IOUtils.toString(inputStream); //this test variable have "{\"name\":\"Camilo\",\"functionName\":\"hello\"}"
lambdaExecutor.handleRequest(inputStream,outputStream);
}
}
and this:
public class LambdaExecutor{
private FrontController frontController;
public LambdaExecutor(){
this.frontController = new FrontController();
}
public void handleRequest(InputStream inputStream, OutputStream outputStream) throws IOException {
//Service service = frontController.findService(inputStream);
String test = IOUtils.toString(inputStream); //this test variable have "" <-empty String
System.exit(0);
//service.execute(inputStream, outputStream, context);
}
}
I used the debug tool, and the InputStream object is the same in both classes

By the time that you've passed the stream into handleRequest(), you've already consumed the stream:
public static void main(String [] args) throws IOException {
InputStream inputStream = new ByteArrayInputStream("{\"name\":\"Camilo\",\"functionName\":\"hello\"}".getBytes());
OutputStream outputStream = new ByteArrayOutputStream();
LambdaExecutor lambdaExecutor = new LambdaExecutor();
String test = IOUtils.toString(inputStream); //this consumes the stream, and nothing more can be read from it
lambdaExecutor.handleRequest(inputStream,outputStream);
}
When you took that out, the method worked as, as you said in the comments.
If you want the data to be re-useable, you'll have to use the reset() method if you want the same data again, or close and re-open the stream to re-use the object with different data.
// have your data
byte[] data = "{\"name\":\"Camilo\",\"functionName\":\"hello\"}".getBytes();
// open the stream
InputStream inputStream = new ByteArrayInputStream(data);
...
// do something with the inputStream, and reset if you need the same data again
if(inputStream.markSupported()) {
inputStream.reset();
} else {
inputStream.close();
inputStream = new ByteArrayInputStream(data);
}
...
// close the stream after use
inputStream.close();
Always close the stream after you use it, or use a try block to take advantage of AutoCloseable; you can do the same with the output stream:
try (InputStream inputStream = new ByteArrayInputStream(data);
OutputStream outputStream = new ByteArrayOutputStream()) {
lambdaExecutor.handleRequest(inputStream, outputStream);
} // auto-closed the streams

The reason you can't is because you can only read from a stream once.
To be able to read twice, you must call the reset() method for it to return to the beginning. After reading, call reset() and you can read it again!
Some sources don't support resetting it so you would actually have to create the stream again. To check if the source supports it, use the markSupported() method of the stream!

Related

Reading/Writing objects to file returning null

I'm trying to read and write objects into a file. Reading the output into a new object works, but every value is null.
Here's the code:
public void read() throws Exception
{
try
{
FileInputStream fIn = new FileInputStream(file);
ObjectInputStream in = new ObjectInputStream(fIn);
Object obj = in.readObject();
System.out.println(obj);
public void save() throws Exception
{
FileOutputStream fOut = new FileOutputStream(file.toString());
ObjectOutputStream out = new ObjectOutputStream(fOut);
out.writeObject(this);
out.flush();
out.close();
}
Here is the file output: (image of output)
I'd like to receive the values I previously wrote to the file in the new object created, however all I get is null for all values.
Edit: since people are asking for the entire class, and I have no idea what code could be causing what, here's the entire UserFile class: https://pastebin.com/Gr1tcGsg
I have ran that code and it works which means you most likely read before you write or you got an exception such as InvalidClassException: no valid constructor which would make sense in your case.
The code I ran:
public class SavedObject implements Serializable
{
public static void main(String[] args) throws IOException, ClassNotFoundException
{
new SavedObject();
}
private final int random;
private SavedObject() throws IOException, ClassNotFoundException
{
random = ThreadLocalRandom.current().nextInt();
File file = new File("Object.txt");
save(file);
read(file);
}
private void save(File file) throws IOException
{
FileOutputStream fileOutput = new FileOutputStream(file);
ObjectOutputStream objectOutput = new ObjectOutputStream(fileOutput);
objectOutput.writeObject(this);
objectOutput.close();
fileOutput.close();
System.out.println(this);
}
private void read(File file) throws IOException, ClassNotFoundException
{
FileInputStream fileInput = new FileInputStream(file);
ObjectInputStream objectInput = new ObjectInputStream(fileInput);
Object obj = objectInput.readObject();
System.out.println(obj);
objectInput.close();
fileInput.close();
}
public String toString()
{
return "SavedObject(Random: " + random + ")";
}
}
Which prints:
SavedObject(Random: -2145716528)
SavedObject(Random: -2145716528)
Also a few tips for you:
Don't have a try-catch if you throws
Have more readable variable names
Send more code in your next question
ObjectOutputStream is not recommended, if you can, you should write the values as they are
Don't use throws "Exception" instead use throws "
Put the file in instead of file.toString()
I found the problem, it was that in my constructor I wasn't correctly applying the retrieved info from the file. Thanks for everyone's help.

How to assert response in zipoutputstream

I am trying to write JUnit using MockitoJUnitRunner.
I am passing file id to my function which is downloading file from cloud and returning zip file as download.
here is my code
public void getLogFile(HttpServletResponse response, String id) throws IOException {
response.setContentType("Content-type: application/zip");
response.setHeader("Content-Disposition", "attachment; filename=LogFiles.zip");
ServletOutputStream out = response.getOutputStream();
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(out));
zos.putNextEntry(new ZipEntry(id));
InputStream inputStream = someDao.getFile(id);
BufferedInputStream fif = new BufferedInputStream(inputStream);
int data = 0;
while ((data = fif.read()) != -1) {
zos.write(data);
}
fif.close();
zos.closeEntry();
zos.close();
}
And my JUnit function is
#Mock
private MockHttpServletResponse mockHttpServletResponse;
anyInputStream = new ByteArrayInputStream("test data".getBytes());
#Test
public void shouldDownloadFile() throws IOException {
ServletOutputStream outputStream = mock(ServletOutputStream.class);
when(mockHttpServletResponse.getOutputStream()).thenReturn(outputStream);
=> when(someDao.download(anyString())).thenReturn(anyInputStream);
controller.getLogFile(mockHttpServletResponse, id);
verify(mockHttpServletResponse).setContentType("Content-type: application/zip");
verify(mockHttpServletResponse).setHeader("Content-Disposition","attachment; filename=LogFiles.zip");
verify(atmosdao).download(atmosFilePath);
}
This unit test is passing but I want to verify what is written on outputStream, how can I do it ? as I am writing "test data" to mocked outputStream like
anyInputStream = new ByteArrayInputStream("test data".getBytes());
when(someDao.download(anyString())).thenReturn(anyInputStream);
mockHttpServletResponse.getContentAsString() is giving me null !
Is it possible to assert MockHttpServletResponse which is written using zipoutputStream ? if yes then how can i do it ?
Thanks.
Instead of mocking your OutputStream, you could create a custom one:
public class CustomOutputStream extends ServletOutputStream {
private ByteArrayOutputStream out = new ByteArrayOutputStream();
private String content;
#Override
public void write(int b) throws IOException {
out.write(b);
}
#Override
public void close() throws IOException {
content = new String(out.toByteArray());
out.close();
super.close();
}
public String getContentAsString() {
return this.content;
}
}
This class will store all the bytes written to it and keep them in the content field.
Then you replace this:
ServletOutputStream outputStream = mock(ServletOutputStream.class);
by this:
CustomOutputStream outputStream = new CustomOutputStream();
When your servlet calls getOutputStream(), it will use the custom one, and in the end getContentAsString() will return you the output that was written to your servlet.
Note: the output is zipped, so the String will contain strange characters. If you want the original string, you'll have to unzip it (and in this case I'd use the byte array returned by out.toByteArray() instead of the String, because when you create a String this way you can have encoding problems when calling string.getBytes())
I got what I was looking for...
This is what I did to assert data written to zipoutputStream using powerMockito.
#Test
public void ShouldAttemptToWriteDownloadedFileToZipOutputStream() throws Exception {
InputStream anyInputStream = new ByteArrayInputStream("test data".getBytes());
ServletOutputStream outputStream = mock(ServletOutputStream.class);
BufferedOutputStream bufferedOutputStream = Mockito.mock(BufferedOutputStream.class);
PowerMockito.whenNew(BufferedOutputStream.class).withArguments(outputStream).thenReturn(bufferedOutputStream);
ZipOutputStream zipOutputStream = Mockito.mock(ZipOutputStream.class);
PowerMockito.whenNew(ZipOutputStream.class).withArguments(bufferedOutputStream).thenReturn(zipOutputStream);
BufferedInputStream bufferedInputStream = new BufferedInputStream(anyInputStream);
PowerMockito.whenNew(BufferedInputStream.class).withArguments(anyInputStream).thenReturn(bufferedInputStream);
subjectUnderTest.getLogFile(mockHttpServletResponse, "12345");
int data = 0;
while ((data = bufferedInputStream.read()) != -1) {
verify(zipOutputStream).write(data);
}
}
Thanks Hugo for your help !

Read objects in a file with Camel?

I have a file containing java objects, wrote with this code:
from(somewhere).process(new Processor() {
#Override
public void process(final Exchange exchange) {
...
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = new ObjectOutputStream(bos);
out.writeObject(myObject);
exchange.getOut().setBody(bos.toByteArray());
}
}).to("file://pathFile");
And now, I want read them fastly. I don't know how can I do that, something like the following code I gess.
from("file://pathFile").convertBodyTo(String.class)
.split(body().tokenize("???")) // How can I tokenize my file ?
.streaming().threads(2)
.process(new Processor() {
#Override
public void process(final Exchange exchange) {
String filePath = (String) exchange.getIn().getHeader(Exchange.FILE_PATH);
File file = new File(filePath);
MyObject myObject = null;
try {
FileInputStream fis = new FileInputStream(file);
InputStream buffer = new BufferedInputStream(fis);
ObjectInput input = new ObjectInputStream(buffer);
Object obj = null;
while ((obj = input.readObject()) != null) {
// Do something
myObject = obj;
}
} catch (Exception e) {
...
} finally {
...
}
exchange.getIn().setBody(myObject);
}
}).to(somewhere);
EDIT: I edit my way to read object. There is still a problem with that code, we can't append to an ObjectOutputStream. That will corrupt the stream. There is a solution [here] for this problem. We can only write the stream header one time.
But If I do that, I wont be able to split and read my file with multiple threads. So can I split or access my file on ObjectOutputStream header ?
you just converted it to a String using convertBodyTo(String.class), therefore you have a String in the body rather than an InputStream....

How to send XML data through socket InputStream

I'm trying to write a client-server application in Java with an XML-based protocol.
But I have a great problem!
See this part of client code:
InputStream incoming = skt.getInputStream(); //I get Stream from Socket.
OutputStream out = skt.getOutputStream();
[...]
XMLSerializer serializer = new XMLSerializer();
//This create an XML document.
tosend = WUTPClientWriter.createMessage100(projectid, cpuclock, cpunumber);
serializer.setOutputByteStream(out);
serializer.serialize(tosend);
At this point server fall in deadlock. It wait for EOF but I can't send it because if I use
out.close();
or
skt.shutdownOutput();
I close the Socket and I must keep this connection alive.
I can't send '\0' becouse I get Parse Error in the server.
How can I do it? Can I "close" the output stream without closing the socket?
RESOLVED
I've created new class XMLStreamOutput and XMLStreamInput with advanced Stream gesture.
I've resolved with this four class:
1)
public class XMLOutputStream extends ByteArrayOutputStream {
private DataOutputStream outchannel;
public XMLOutputStream(OutputStream outchannel) {
super();
this.outchannel = new DataOutputStream(outchannel);
}
public void send() throws IOException {
byte[] data = toByteArray();
outchannel.writeInt(data.length);
outchannel.write(data);
reset();
}
}
2)
public class XMLSender {
public static void send(Document tosend, OutputStream channel) throws TransformerConfigurationException, IOException {
XMLOutputStream out = new XMLOutputStream(channel);
StreamResult sr = new StreamResult(out);
DOMSource ds = new DOMSource(tosend);
Transformer tf = TransformerFactory.newInstance().newTransformer();
try {
tf.transform(ds, sr);
} catch (TransformerException ex) {
Logger.getLogger(XMLSender.class.getName()).log(Level.SEVERE, null, ex);
}
out.send();
}
}
3)
public class XMLInputStream extends ByteArrayInputStream {
private DataInputStream inchannel;
public XMLInputStream(InputStream inchannel) {
super(new byte[2]);
this.inchannel = new DataInputStream(inchannel);
}
public void recive() throws IOException {
int i = inchannel.readInt();
byte[] data = new byte[i];
inchannel.read(data, 0, i);
this.buf = data;
this.count = i;
this.mark = 0;
this.pos = 0;
}
}
4)
public class XMLReceiver {
public static Document receive(InputStream channel) throws ParserConfigurationException, TransformerConfigurationException, IOException, SAXException {
DocumentBuilderFactory docBuilderFact = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFact.newDocumentBuilder();
Document request = null;
XMLInputStream xmlin = new XMLInputStream(channel);
xmlin.recive();
request = docBuilder.parse(xmlin);
return request;
}
}
You don't want to close the socket's OutputStream, because the socket only has one OutputStream.
It looks like you just need to flush your OutputStream after writing to it.
out.flush();
EDIT: Thanks for the extra info. If you're reading the socket like this, receiver needs to know when you're done writing. An InputStream only knows you're done writing if you close the socket.
But since you have already stated you can't close the socket, you need another way of telling the receiving side that you're done. You either need to use a special type of stream which knows about the data being sent, or you need to set up a contract for writing/reading the appropriate amount of data.
It would probably be easiest to send the data as an Object (using ObjectOutputStream/ObjectInputStream--maybe you don't even need to convert to XML).
If you don't want the overhead associated with Object streams, the simple solution is to compute the length of the data being sent, and send that number just prior to sending the actual data. In this case, you can use a DataOutputStream/DataInputStream. Send the number of bytes to read, followed by the data. On the receiving side, read the number, then read the given number of bytes into a temporary variable and feed that to DocumentBuilder.parse(InputStream).
On the sending end, you would do this:
DataOutputStream out = new DataOutputStream(s.getOutputStream());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XMLSerializer serializer = new XMLSerializer();
serializer.setOutputByteStream(baos);
tosend = WUTPClientWriter.createMessage100(projectid, cpuclock, cpunumber);
serializer.serialize(tosend);
out.writeInt(baos.size());
out.write(baos.toByteArray());
out.flush();
Then on the receiving end, you do something like the following:
DataInputStream in = new DataInputStream(s.getInputStream());
int len = in.readInt();
byte[] xml = new byte[len];
in.read(xml, 0, len);
Document doc = builder.parse(new ByteArrayInputStream(xml));

How to decompress a gzipped data in a byte array?

I have a class which has a method that is receiving an object as a parameter.
This method is invoked via RMI.
public RMIClass extends Serializable {
public RMIMethod(MyFile file){
// do stuff
}
}
MyFile has a property called "body", which is a byte array.
public final class MyFile implements Serializable {
private byte[] body = new byte[0];
//....
public byte[] getBody() {
return body;
}
//....
}
This property holds the gzipped data of a file that was parsed by another application.
I need to decompress this byte array before performing further actions with it.
All the examples I see of decompressing gzipped data assume that I want to write it to the disk and create a physical file, which I do not.
How do I do this?
Thanks in advance.
Wrap your byte array with a ByteArrayInputStream and feed it into a GZipInputStream
Look at those samples, and wherever they're using FileOutputStream, use ByteArrayOutputStream instead. Wherever they're using FileInputStream, use ByteArrayInputStream instead. The rest should be simple.
JDK 9+
private byte[] gzipUncompress(byte[] compressedBytes) throws IOException {
try (InputStream inputStream = new GZIPInputStream(new ByteArrayInputStream(compressedBytes))) {
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
inputStream.transferTo(outputStream);
return outputStream.toByteArray();
}
}
}
Why don't you create your own class that extends OutputStream or , whatever is the archive writing to ?
If you want to write to a ByteBuffer you can do this.
private static void uncompress(final byte[] input, final ByteBuffer output) throws IOException
{
final GZIPInputStream inputGzipStream = new GZIPInputStream(new ByteArrayInputStream(input));
Channels.newChannel(inputGzipStream).read(output);
}

Categories