Java equivalent to python's "with" - java

Python has a nice feature: the "with" statement. It's useful for making global changes that affect all code called within the statement.
e.g. you could define a class CapturePrintStatements to capture all print statements called within the "with"
with CapturePrintStatements() as c:
print 'Stuff Done'
print 'More Stuff Done'
assert c.get_text() == 'Stuff Done'
Is there an equivalent in Java?

try-with-resources is its Java equivalent, and is available in Java 7 and up.
That gives you the possibility to work with resources that need to be explicitly closed, without worrying about closing them. For the example:
Before Java7:
InputStream input = null;
try {
input = new FileInputStream("myFile.txt");
} finally {
if(input != null){
input.close();
}
}
Java 7 & up:
try(FileInputStream input = new FileInputStream("myFile.txt")) {
// Do something with the InputStream
}
This is the try-with-resources construct. When the execution flow will go out of the try block, the FileInputStream will be closed automatically. This is due to the fact that FileInputStream implements the AutoCloseable interface.

As Mohammed noted, you can use try-with-resources. In this case, you want to have your own resource, and it is not really difficult to do.
Creating an auto-closeable class
First, your class should implement AutoCloseable:
public class CaptureOutput implements AutoCloseable {
When constructing this class, you should
store the old System.out,
create a PrintStream to replace it (cf. Java: PrintStream to String?) and
replace the default stream with System.setOut().
Here is how we do it
public CaptureOutput() {
this.stream = new ByteArrayOutputStream();
this.out = System.out;
System.setOut(new PrintStream(stream));
}
The secret is the AutoCloseable.close() method: you just undo your replacement there:
public void close() throws Exception {
System.setOut(this.out);
}
Finally, you need a method to retrieve the content:
public String getContent() {
return this.stream.toString();
}
Using try-with-resources
Done that, just pass the CaptureOutput to the try clause. The code below, for example...
public static void main(String[] args) throws Exception {
String content = null;
System.out.println("This will be printed");
try (CaptureOutput co = new CaptureOutput()) {
System.out.println("EXAMPLE");
content = co.getContent();
}
System.out.println("This will be printed, too.");
System.out.println("The content of the string is " + content);
}
...will result on this:
This will be printed
This will be printed, too.
The content of the string is EXAMPLE
Scope issues
Note that we do not call co.getContent() at the last line. It is not possible because, unlike Python, the co variable is scoped inside the try clause. Once the try block finishes, it is gone.[1] That's why we get the value from inside the block.
Not that elegant, right? A solution may be to give the BAOS to the CaptureOutput constructor:
public CaptureOutput(ByteArrayOutputStream stream) {
this.stream = stream;
this.out = System.out;
System.setOut(new PrintStream(this.stream));
}
Now, we just use the stream later:
public static void main(String[] args) throws Exception {
System.out.println("This will be printed");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try (CaptureOutput co = new CaptureOutput(stream)) {
System.out.println("EXAMPLE");
}
System.out.println("This will be printed, too.");
System.out.println("The content of the string is " + stream.toString());
}
(Also, it is not possible to create the CaptureOutput variable before the try. That makes sense: AutoCloseable objects are supposed to be "closed" after their use. What's the use of a closed file, after all? Our use case is a bit different from that, so we have to rely on alternatives.)
The full classes
And here are the full classes:
CaptureOutput.java:
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
public class CaptureOutput implements AutoCloseable {
private ByteArrayOutputStream stream;
private PrintStream out;
public CaptureOutput(ByteArrayOutputStream stream) {
this.stream = stream;
this.out = System.out;
System.setOut(new PrintStream(this.stream));
}
public CaptureOutput() {
this(new ByteArrayOutputStream());
}
#Override
public void close() throws Exception {
System.setOut(this.out);
}
public String getContent() {
return this.stream.toString();
}
}
Main.java:
import java.io.ByteArrayOutputStream;
public class Main {
public static void main(String[] args) throws Exception {
System.out.println("This will be printed");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try (CaptureOutput co = new CaptureOutput(stream)) {
System.out.println("EXAMPLE");
}
System.out.println("This will be printed, too.");
System.out.println("The content of the string is " + stream.toString());
}
}

Related

JDK 7: Existing file gets empty on new File("path/to/file.html");

I'm using JDK 7. I've got a class with a method that creates a html-file using PrintStream. Another method in the same class is supposed to use the created file and do stuff with it. The problem is that once i use new File("path/to/file.html), the file lenght is reduced to 0. My code:
public class CreatePDFServiceImpl {
private final PrintStream printStream;
public CreatePDFServiceImpl() throws IOException {
printStream = new PrintStream("/mnt/test.html", "UTF-8");
}
public void createHtmlFile() throws IncorporationException {
try {
StringBuilder html = new StringBuilder();
HtmlFragments htmlFragments = new HtmlFragments();
html.append(htmlFragments.getHtmlTop())
.append(htmlFragments.getHeading())
.append(htmlFragments.buildBody())
.append(htmlFragments.buildFooter());
printStream.print(html.toString());
} finally {
if(printStream != null) {
printStream.close();
}
}
}
This next method is supposed to use the html file created in "createHtmlFile()":
public void convertHtmlToPdf() {
PrintStream out = null;
try {
File file = new File("/mnt/test.html");
/** this code added just for debug **/
if (file.createNewFile()){
System.out.println("File is created!");
} else {
System.out.println("File already exists. size: " + file.length());
}
/* PDF generation commented out. */
//out = new PrintStream("/mnt/testfs.pdf", "UTF-8");
//defaultFileWriter.writeFile(file, out, iTextRenderer);
} catch (IOException e) {
throw new IncorporationException("Could not save pdf file", e);
} finally {
if(out != null) {
out.close();
}
}
My junit integration test class:
#Category(IntegrationTest.class)
public class CreatePDFServiceIntegrationTest {
private static CreatePDFServiceImpl createPDFService;
#BeforeClass
public static void init() throws IOException {
createPDFService = new CreatePDFServiceImpl();
}
#Test
public void testCreateHtmlFile() throws IncorporationException {
createPDFService.createHtmlFile();
File createdFile = new File("/mnt/test.html");
System.out.println("createdFile.length() = " + createdFile.length());
Assert.assertTrue(createdFile.length() > 1);
}
#Test
public void testCreatePDF() throws Exception {
File fileThatShouldExist = new File("/mnt/testfs.pdf");
createPDFService.convertHtml2Pdf();
Assert.assertTrue(fileThatShouldExist.exists());
}
}
The first test passes, output:
"createdFile.length() = 3440".
I checked the file system, there is the file. size 3,44kb.
Second test fails, output from CreatePDFServiceImpl:
"File already exists. size: 0"
Looking in the file system, the file now is actually 0 bytes.
I'm stumped. The new File("path") should only create a reference to that file and not empty it?
I doubt there's an error in File.createNewFile(). I don't yet fully grasp in which order you run your code, but are you aware that this sets the file size to zero?
out = new PrintStream("/mnt/testfs.pdf", "UTF-8");
From the PrintStream(File file) Javadoc:
file - The file to use as the destination of this print stream. If the
file exists, then it will be truncated to zero size; otherwise, a new
file will be created. The output will be written to the file and is
buffered.
I think that's the culprit - but in your code that line is commented out. Am I right you have run your tests with that line commented in?

How do I create stubs for IO files to unit test in Java?

For a testing course assignment, I need to create unit tests for my already-coded system using JUnit. My system is heavily dependent on each other and it also writes/reads from a couple of text files on my disk.
I realize I have to eliminate all dependancies to successfully unit test, I just don't know how to create stubs for Files.
Any help in code, tools or concepts is welcome
import Objs.*;
import java.io.*;
import java.net.URL;
import java.util.Scanner;
/**
*This class communicates with the users file by writing to it, reading from it, searching, deleting...
*
*/
public class users {
public static File usersFile = new File("usersFile.txt");
public static PrintWriter writer;
static Scanner read ;
public static void write(userObj u){
try {
String gather = read();
String newUser = u.toString();
writer = new PrintWriter(usersFile);
writer.append(gather).append(newUser).append("\n");
writer.close();
System.out.println("The users' file has been updated");
}
catch(FileNotFoundException ex){
System.out.print("file not found");
}
}
public static String read(){
String f = null;
try {
read = new Scanner(usersFile);
StringBuilder gather = new StringBuilder();
while(read.hasNext()){
gather.append(read.nextLine()).append("\n");
}
f = gather.toString();
}
catch(FileNotFoundException ex){
System.out.print("file not found");
}
return f;
}
public static userObj search(String s){
userObj foundUser = null;
try {
read = new Scanner(usersFile);
String st=null;
while(read.hasNext()){
if (read.next().equalsIgnoreCase(s)){
foundUser = new userObj();
foundUser.name = s;
foundUser.setType(read.next().charAt(0));
foundUser.credit = read.nextDouble();
}
}
}
catch(FileNotFoundException ex){
System.out.print("file not found");
}
return foundUser;
}
public static void remove(userObj u){
String s = u.name;
if (search(s) == null){
return;}
try {
read = new Scanner(usersFile);
StringBuilder gather = new StringBuilder();
while(read.hasNext()){
String info = read.nextLine();
if (info.startsWith(s)){
continue;
}
gather.append(info).append("\n");
}
writer = new PrintWriter(usersFile);
writer.append(gather).append("\n");
writer.close();
System.out.println("The user has been deleted");
}
catch(FileNotFoundException ex){
System.out.print("file not found");
}}
public static void update(userObj u){
remove(u);
write(u);
}
}
You don't need to create "stubs for files", you need to create "stub for reading from an InputStream".
For read, search, and remove you're using Scanner, which accepts an InputStream as one of its overloaded constructors. If you add an InputStream parameter, you can use that to construct your Scanner. With normal use, you can pass a FileInputStream, while using a StringBufferInputStream for testing.
For write and remove you're using a PrintWriter, which accepts an OutputStream as one of its overloaded constructors. If you add an OutputStream parameter, you can use that to construct your PrintWriter. With normal use, you can pass a FileOutputStream, while using a ByteArrayOutputStream for testing. If you want to read the result as a string from your test, use toString(String charsetName).
public class Users {
...
public static void write(UserObj u, InputStream input, OutputStream output) {
...
String gather = read(input);
...
writer = new PrintWriter(output);
...
}
public static String read(InputStream input) {
...
read = new Scanner(input);
...
}
public static UserObj search(String s, InputStream input) {
...
read = new Scanner(input);
...
}
public static void remove(UserObj u, InputStream input, OutputStream output) {
...
read = new Scanner(input);
...
writer = new PrintWriter(output);
...
}
public static void update(UserObj u, InputStream input, OutputStream output) {
remove(u, input, output);
write(u, input, output);
}
}
// Client code example
FileInputStream input = new FileInputStream("usersFile.txt");
FileOutputStream output = new FileOutputStream("usersFile.txt");
...
Users.write(myUser, input, output);
...
String result = Users.read(input);
...
myUser = Users.search(myString, input);
...
Users.remove(myUser, input, output);
...
Users.update(myUser, input, output);
// Testing code example
StringBufferInputStream input = new StringBufferInputStream("...");
ByteArrayOutputStream output = new ByteArrayOutputStream();
...
Users.write(myUser, input, output);
...
String result = Users.read(input);
...
myUser = Users.search(myString, input);
...
Users.remove(myUser, input, output);
...
Users.update(myUser, input, output);
...
result = output.toString("UTF-8"); // see docs for other legal charset names

Testing output of void main with Console.readline() involved

I need to junit test an existing code by the output ( in system.out )
public static void main(String args[])
{
Console console = System.console();
String str = console.readLine();
System.out.println("halo"+str);
}
Since the console.readline is waiting for user input, I found it will halt in the console.readline(),thus block me from getting the output.
Is there a way to do this? Is it posible to do it using Mockito or something?
It is nearly impossible to test code that works with System.console(), because you System.console() always retuns null in tests. Additionally Console is final class without a public constructor.
I recommend to work with the writers and readers of Console and test the code that works with the writers and readers.
public static void main(String args[]) {
Console console = System.console();
BufferedReader reader = new BufferedReader(console.reader());
main2(reader, console.writer(), args);
}
static void main2(BufferedReader reader, Writer writer, String args[] {
String str = reader.readline();
System.out.println("halo"+str);
}
Output to System.out can be tested with the StandardOutputStreamLog rule of the System Rules library. But in your code it is much easier to write to the Console's writer instead of System.out.
The main method is not a good candidate for unit testing. It is just an entry point for an application. Probably, you need to refactor your class to some kind of dependency injection. For example:
public class Something {
private final LinesProvider linesProvider;
public Something(LinesProvider linesProvider) {
this.linesProvider = linesProvider;
}
public void sayHello() {
String str = linesProvider.readLine();
System.out.println("halo "+str);
}
public static void main(String args[]) {
new Something(new LinesProvider() {
private final Console console = System.console();
#Override
public String readLine() {
return console.readLine();
}
}).sayHello();
}
}
interface LinesProvider {
String readLine();
}
Then, you can test the system output like shown below, though it's not a good practice. Instead, try to separate I/O logic from application logic:
public class TestSomething {
private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
private PrintStream printStream = new PrintStream(outputStream, true);
#Before
public void setUp() {
System.setOut(printStream);
}
#Test
public void test() {
new Something(new LinesProvider() {
#Override
public String readLine() {
return "Vasya";
}
}).sayHello();
assertEquals("halo Vasya" + System.getProperty("line.separator"), new String(outputStream.toByteArray()));
}
}
The following test will work, using the JMockit mocking API:
#Test
public void testMyApp(#Mocked final Console console)
{
new NonStrictExpectations(System.class) {{
System.console(); result = console;
console.readLine(); result = " test";
}};
OutputStream output = new ByteArrayOutputStream();
System.setOut(new PrintStream(output));
MyApp.main(new String[0]);
String lineSep = System.getProperty("line.separator");
assertEquals("halo test" + lineSep, output.toString());
}

Java - How Can I Write My ArrayList to a file, and Read (load) that file to the original ArrayList?

I am writing a program in Java which displays a range of afterschool clubs (E.G. Football, Hockey - entered by user). The clubs are added into the following ArrayList:
private ArrayList<Club> clubs = new ArrayList<Club>();
By the followng Method:
public void addClub(String clubName) {
Club club = findClub(clubName);
if (club == null)
clubs.add(new Club(clubName));
}
'Club' is a class with a constructor - name:
public class Club {
private String name;
public Club(String name) {
this.name = name;
}
//There are more methods in my program but don't affect my query..
}
My program is working - it lets me add a new Club Object into my arraylist, i can view the arraylist, and i can delete any that i want etc.
However, I now want to save that arrayList (clubs) to a file, and then i want to be able to load the file up later and the same arraylist is there again.
I have two methods for this (see below), and have been trying to get it working but havent had anyluck, any help or advice would be appreciated.
Save Method (fileName is chosen by user)
public void save(String fileName) throws FileNotFoundException {
String tmp = clubs.toString();
PrintWriter pw = new PrintWriter(new FileOutputStream(fileName));
pw.write(tmp);
pw.close();
}
Load method (Current code wont run - File is a string but needs to be Club?
public void load(String fileName) throws FileNotFoundException {
FileInputStream fileIn = new FileInputStream(fileName);
Scanner scan = new Scanner(fileIn);
String loadedClubs = scan.next();
clubs.add(loadedClubs);
}
I am also using a GUI to run the application, and at the moment, i can click my Save button which then allows me to type a name and location and save it. The file appears and can be opened up in Notepad but displays as something like Club#c5d8jdj (for each Club in my list)
You should use Java's built in serialization mechanism.
To use it, you need to do the following:
Declare the Club class as implementing Serializable:
public class Club implements Serializable {
...
}
This tells the JVM that the class can be serialized to a stream. You don't have to implement any method, since this is a marker interface.
To write your list to a file do the following:
FileOutputStream fos = new FileOutputStream("t.tmp");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(clubs);
oos.close();
To read the list from a file, do the following:
FileInputStream fis = new FileInputStream("t.tmp");
ObjectInputStream ois = new ObjectInputStream(fis);
List<Club> clubs = (List<Club>) ois.readObject();
ois.close();
As an exercise, I would suggest doing the following:
public void save(String fileName) throws FileNotFoundException {
PrintWriter pw = new PrintWriter(new FileOutputStream(fileName));
for (Club club : clubs)
pw.println(club.getName());
pw.close();
}
This will write the name of each club on a new line in your file.
Soccer
Chess
Football
Volleyball
...
I'll leave the loading to you. Hint: You wrote one line at a time, you can then read one line at a time.
Every class in Java extends the Object class. As such you can override its methods. In this case, you should be interested by the toString() method. In your Club class, you can override it to print some message about the class in any format you'd like.
public String toString() {
return "Club:" + name;
}
You could then change the above code to:
public void save(String fileName) throws FileNotFoundException {
PrintWriter pw = new PrintWriter(new FileOutputStream(fileName));
for (Club club : clubs)
pw.println(club); // call toString() on club, like club.toString()
pw.close();
}
In Java 8 you can use Files.write() method with two arguments: Path and List<String>, something like this:
List<String> clubNames = clubs.stream()
.map(Club::getName)
.collect(Collectors.toList())
try {
Files.write(Paths.get(fileName), clubNames);
} catch (IOException e) {
log.error("Unable to write out names", e);
}
This might work for you
public void save(String fileName) throws FileNotFoundException {
FileOutputStream fout= new FileOutputStream (fileName);
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(clubs);
fout.close();
}
To read back you can have
public void read(String fileName) throws FileNotFoundException {
FileInputStream fin= new FileInputStream (fileName);
ObjectInputStream ois = new ObjectInputStream(fin);
clubs= (ArrayList<Clubs>)ois.readObject();
fin.close();
}
ObjectOutputStream.writeObject(clubs)
ObjectInputStream.readObject();
Also, you 'add' logic is logically equivalent to using a Set instead of a List. Lists can have duplicates and Sets cannot. You should consider using a set. After all, can you really have 2 chess clubs in the same school?
To save and load an arraylist of
public static ArrayList data = new ArrayList ();
I used (to write)...
static void saveDatabase() {
try {
FileOutputStream fos = new FileOutputStream("mydb.fil");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(data);
oos.close();
databaseIsSaved = true;
}
catch (IOException e) {
e.printStackTrace();
}
} // End of saveDatabase
And used (to read) ...
static void loadDatabase() {
try {
FileInputStream fis = new FileInputStream("mydb.fil");
ObjectInputStream ois = new ObjectInputStream(fis);
data = (ArrayList<User>)ois.readObject();
ois.close();
}
catch (IOException e) {
System.out.println("***catch ERROR***");
e.printStackTrace();
}
catch (ClassNotFoundException e) {
System.out.println("***catch ERROR***");
e.printStackTrace();
}
} // End of loadDatabase

Extending OutputStream class; write(int) method

So my goal is to implement the write method in the class OutputStream to create a new class NumStream, which basically converts ints to Strings. Here is my sample code:
import java.io.*;
public class NumStream extends OutputStream {
public void write(int c) throws IOException {
// What goes here?
}
public static void main(String[] args) {
NumStream ns = new NumStream();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(ns));
pw.println("123456789 and ! and # ");
pw.flush(); // needed for anything to happen, try taking it out
}
}
I've tried using several different approaches, and my result always results in the program compiling, but when I run it, nothing happens. So far I've tried using switch statements to produce this result:
public void write(int c) throws IOException {
StringBuffer sb = new StringBuffer();
switch (c) {
case 1: sb.append("1");
break;
//etc. through 9
I'm unsure of what to do or try next to produce a result. :/ Any tips to steer me in the right direction?
I had the same problem too, Here is the solution:
public class MyOutputStream extends OutputStream {
StringBuilder anotatedText;
public MyOutputStream() {
// Custom constructor
}
#Override
public void write(int b) {
int[] bytes = {b};
write(bytes, 0, bytes.length);
}
public void write(int[] bytes, int offset, int length) {
String s = new String(bytes, offset, length);
anotatedText.append(s);
}
public void myPrint() {
System.out.println(anotatedText);
}
}
All we need to do is to implement the "write" method correctly which is clearly instructed in the above example.

Categories

Resources