Is there any good way of using try-with-resources when opening an InputStream in a constructor and then passing that to a super constructor?
Basically what I want to do is this:
public class A {
public A(InputStream stream) {
// Do something with the stream but don't close it since we didn't open it
}
}
public class B {
public B(File file) {
// We open the stream so we need to ensure it's properly closed
try (FileInputStream stream = new FileInputStream(file)) {
super(new FileInputStream(file));
}
}
}
But, of course, since super must be the first statement in the constructor this isn't allowed. Is there any good way of achieving this?
Consider using a static factory method instead of using the constructor directly. Make at least B's constructor private, and create a method such as
private B(InputStream is) {
super(is);
// Whatever else is needed
}
public static B newInstance(File file) {
B result;
try (FileInputStream stream = new FileInputStream(file)) {
result = new B(stream);
}
// Further processing
return result;
}
Another way to go :
public class A {
protected A(){
// so he can't be called from the outside, subclass ensure that init is done properly.
}
public A(InputStream stream) {
init(stream);
}
// not be able to call it from outside
protected final init(InputStream is){
//here goes the code
}
}
public class B {
public B(File file) {
// We open the stream so we need to ensure it's properly closed
try (FileInputStream stream = new FileInputStream(file)) {
init(stream);
}
}
}
I'm posting this here as a possible answer, however here i'm consdering :
You can update A's code
You're moving constructor's code to an init method, thanks to protected empty arg constructor, only subclasses have to handle the call to init properly. Some may see that as not so well designed. My point is as soon your subclassing something, you have to know more about it that just when you just using it.
Sadly I do not have a compiler on hand to test on but could you not do as follows.
public class B {
private static InputStream file2stream(File f){
// We open the stream so we need to ensure it's properly closed
try (FileInputStream stream = new FileInputStream(file)) {
return stream;
}catch(/*what you need to catch*/){
//cleanup
// possibly throw runtime exception
}
}
public B(File file) {
super(file2stream(file))
}
}
Related
I am building a simple logger class-
public class MyLogger {
private final PrintWriter errorWriter;
public MyLogger(OutputStream outputStream) {
final Writer errorStreamWriter = new OutputStreamWriter(outputStream);
this.errorWriter = new PrintWriter(errorStreamWriter);
}
public void start() {
errorWriter.flush();
}
public void addError(String errorMessage) {
errorWriter.println(errorMessage);
}
public void finish() {
errorWriter.flush();
errorWriter.close();
}
}
Now I want to write a unit test to test whether the streams are getting flushed or not, in short if we comment the following methods-
public void start() {
// errorWriter.flush();
}
public void finish() {
// errorWriter.flush();
// errorWriter.close();
}
then the test should fail, I do not wish to use reflection even if it provides a solution, I feel that this isn't possible as we have no control over the errorWriter and other connected streams won't be flushed when the chained stream is flushed, but still, if there is a solution, kindly let me know.
There are some possiblities how you can test this. I am using Mockito as mocking framework in the examples.
I would prefer solution 1) all other are more or less hacks, but the pattern can be useful for more dificult classes which use database connections or other expensive objects.
You test against the public API of you class(like a black box). The caller did not know anything about the internal PrintWriter and has no need to know anything about it.
However you can write a test to ensure the OutputStream is flushed since this is propagated (at least with standard Java Streams). This would fail if you comment out the flush in the start method.
class MyLoggerTest {
OutputStream out = mock(OutputStream.class);
MyLogger myLogger = new MyLogger(out);
#Test
void should_call_flush_out_stream() throws IOException {
myLogger.start();
verify(out).flush();
}
}
You change your class to have a second protected constructor which accepts a PrintWriter. The public constructor uses this one and you use a mock and the second constructor in your test for the flush. The test is similar to the one in 1) but you use a mock(printWriter.class).
public class MyLogger {
private final PrintWriter errorWriter;
public MyLogger(OutputStream outputStream) {
this(new PrintWriter(new OutputStreamWriter(outputStream)));
}
MyLogger(PrintWriter writer) {
this.errorWriter = writer;
}
....
You did not access the PrintWriter directly from the member variable, but create an internal getter method, which can then be used in a Spy to change the internal representation.
public class MyLogger {
private final PrintWriter errorWriter;
...Constructor...
PrintWriter getWriter() {
return errorWriter;
}
public void start() {
getWriter().flush();
}
...
}
And the test would look like this:
class MyLoggerTest {
OutputStream out = mock(OutputStream.class);
PrintWriter writer = mock(PrintWriter.class);
MyLogger myLogger = spy(new MyLogger(out));
#BeforeEach
void setup() {
when(myLogger.getWriter()).thenReturn(writer);
}
#Test
void should_call_flush_out_stream() {
myLogger.start();
verify(writer).flush();
}
}
I'm calling the main method of a class via reflection. For example:
Object o = clasz.getDeclaredConstructor().newInstance();
Method method = clasz.getMethod("main", String[].class);
method.invoke(o, new String[1]);
The called code looks as:
public class Test {
public static void main(String[] args) {
System.out.println("This is a test");
}
}
The reflection works fine and I can see the message in the console.
Is there a way to register something like a binding to the method invocation, for example a PrintWriter or a custom decorated Writer, so I can get the print value as a String?
You can change what System.out is bound to using System.setOut();. You can then make your own:
public class MyTeeingPrinter extends OutputStream {
private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
private final PrintStream original;
public MyTeeingPrinter(PrintStream original) {
this.original = original;
}
#Override public void write(int b) {
original.write(b);
buffer.write(b);
}
public String getAndClear() {
String s = buffer.toString(StandardCharsets.UTF_8);
buffer.reset();
return s;
}
}
And then:
MyTeeingPrinter tee = new MyTeeingPrinter();
System.setOut(new PrintStream(tee));
and now you can invoke tee.getAndClear().
It's a bit of a slog, because whatever code you are running like this is presumably badly designed - it should have instead taken a PrintStream or preferrably an Appendable or Writer, and would write into this writer. Then a trivial one-liner main can be made that just tosses System.out into a writer and hands that to this code you're attempting to run for the case where you just want that code to run and write to sysout, and you can make your own (and stop using reflecting to invoke that main method) and hand that to this code you are running in this scenario.
Note that your reflective code 'works' but is bizarre. There is no need to make a new instance; main is static. The right way is:
Method method = clasz.getMethod("main", String[].class);
method.invoke(null, new String[1]);
That main() method is called in the same process, hence, you can just provide your own stdout implementation/decorator via java.lang.System.setOut(PrintStream) before the reflection magic
An empty string array would work: new String[1] -> new String[0]
You don't need to create a new object to call the static method. Even though java allows calling static methods via objects, this is a bad style and sometimes might cause problems because of name shadowing. Consider the example below:
public class Parent {
public static void main(String[] args) {
Parent child = new Child();
child.test();
}
public static void test() {
System.out.println("Parent.test()");
}
}
class Child extends Parent {
public static void test() {
System.out.println("Child.test()");
}
}
It actually calls Parent.test() even though it's invoked on a Child object
I know that there must be a variable declaration associated with the resource in the try clause.
But as well being assigned a usual resource instantiation, could it instead be assigned an already existing resource eg :
public String getAsString(HttpServletRequest request) throws Exception {
try (BufferedReader in = request.getReader(); ){
etc
}
}
ie. will the BufferedReader be closed automatically just like resources instantiated directly in the try clause ?
Yes. Anything that is AutoCloseable will call the close method. try-with-resource will do that.
We can test whether this is true using this code:
class Main {
public static void main(String[]args) throws Exception {
AutoCloseable _close = getCloseable()
try (AutoCloseable close = _close) {
// ...
}
}
public static AutoCloseable getCloseable() {
return new MyCloseable();
}
}
class MyCloseable implements AutoCloseable {
#Override
public void close() {
System.out.println("Closing");
}
}
The output is "Closing". This means that indeed, AutoCloseables that are created before the try block will still be closed after the try block.
Actually, Java does not care what you put in the () of the try block, as long as it implements AutoCloseable. At runtime, the expression will be automatically evaluated to a value, whether it is a new expression or not.
Yes, BufferedReader will be closed automatically.
Since Java 7, Interface AutoCloseable is added as a SuperInterface of Closeable, so all implementing classes of Closeable (ie. Resource classes) interface automatically inherit AutoCloseable interface.
I came into this whilst spending my night programming.
//Reader class isn't java.io but it's from third party library
public class ACR122U extends Reader {
// This method is called from outside
// This method overrides method of the Reader class
#Override
public void open(UsbDevice device) {
new OpenTask().execute(device);
}
private class OpenTask extends AsyncTask<UsbDevice, Void, Exception> {
#Override
protected Exception doInBackground(UsbDevice... params) {
Exception result = null;
try {
// There the problem (recursion) happens
// I don't want to call ACR122U.open() but Reader.open()
// I cannot call super.open() /super of OpenTask class is AsyncTask/
open(params[0]);
} catch (Exception e) {
result = e;
}
return result;
}
}
}
and I'm wondering if it's possible to solve the problem without changing name of open() method.
Any idea?
PS: Newbie here.
The syntax for what you want to do is:
ACR122U.super.open(params[0]);
However, if you're talking about java.io.Reader, this isn't going to work because the Reader class doesn't define an open() method; certainly not an open(UsbDevice) method.
Let's say I define myself a new type of byte stream (similar to OutputStream):
public interface MyByteStream {
public void write(byte[] data) throws IOException;
}
Also, I have a helper class that can write Strings to a byte stream, and for flexibility, I would like to have two versions of its method, so that it works with either a regular OutputStream or my new MyByteStream:
public class StringWriter {
public void write(String string, MyByteStream stream) throws IOException {
stream.write(string.getBytes());
}
public void write(String string, OutputStream stream) throws IOException {
stream.write(string.getBytes());
}
}
Now, if I have a class that extends OutputStream and implements MyByteStream, like this:
public class DebugStream extends OutputStream implements MyByteStream {
#Override
public void write(int b) throws IOException {
System.out.println(b);
}
}
I can't just call my StringWriter's write method like this:
new StringWriter().write("Hello", new DebugStream());
as it will give me the following error:
The method write(String, MyByteStream) is ambiguous for the type StringWriter
I can resolve the problem by explicitly casting the DebugStream to one of the byte streams, like so:
new StringWriter().write("Hello", (OutputStream) new DebugStream());
new StringWriter().write("Hello", (MyByteStream) new DebugStream());
But since the two methods do the exact same thing anyways, I would much rather not have to do the cast everywhere. Is there some way around this? Like defining one of the methods as preferred for such ambiguous calls? Or maybe some generics-trickery?
Note:
I would like to keep compile-time type-safety alive, so "solutions" along the following lines are out:
public class StringWriter {
public void write(String string, Object stream) throws IOException {
if (stream instanceof OutputStream) {
((OutputStream) stream).write(string.getBytes());
} else if (stream instanceof MyByteStream) {
((MyByteStream) stream).write(string.getBytes());
} else {
throw new IllegalArgumentException();
}
}
}
There are two main options:
1) Name the method differently, rather than overloading the existing one:
public void write(String string, OutputStream stream) {
//
}
public void writeMyByteStream(String string, MyByteStream stream) {
//
}
This is not a good solution, because it pollutes the API with implementation detail, but it's an option.
2) Use one public method, but privately choose how to handle the stream types:
public void write(String string, OutputStream stream) {
if (stream instanceof MyByteStream) {
writeMyByteStream(string, stream);
} else {
writeOutputStream(string, stream);
}
}
private void writeMyByteStream(String string, MyByteStream stream) {
//
}
private void writeOutputStream(String string, OutputStream stream) {
//
}
The cleaner way is this second one, because the API is far simpler and clients don't need to know that the class does any thing special with a MyByteStream. It also means that special support may be withdrawn from the implementation later without changing any client code.
Some may question using instanceof from a style perspective, but when you need it, you need it.