I was wondering if it was possible to require a certain type of file in class constructor?
For example:
private class name(File location.txt)
I want to have a different constructor for each type of file format that I am going to support. I could write a method that checks the file and sends it to the appropriate method, but was wondering if it was a possibility to skip that logic?
I hope this mini factory sample would work for you:
public class Test {
private FileReaderFactory fileReaderFactory = new FileReaderFactory();
public static void main(String[] args) {
String fileTxt = "test1.txt";
String filePdf = "test2.pdf";
Test test = new Test();
FileTypeI filereaderTxt = test.fileReaderFactory.createFromExtension(fileTxt);
FileTypeI filereaderPdf = test.fileReaderFactory.createFromExtension(filePdf);
filereaderTxt.readFile();
filereaderPdf.readFile();
}
public interface FileTypeI {
void readFile();
}
class TextFileReader implements FileTypeI {
#Override
public void readFile() {
//Code to read Text File
}
}
class PDFFileReader implements FileTypeI {
#Override
public void readFile() {
//Code to read PDF File
}
}
class FileReaderFactory {
public FileTypeI createFromExtension (String filename) {
FileTypeI returningValue = null;
if (filename != null && filename.endsWith(".txt")) {
returningValue = new TextFileReader();
}
else if (filename != null && filename.endsWith(".pdf")) {
returningValue = new PDFFileReader();
}
return returningValue;
}
}
}
Related
I would like to know if exists such thing like java parser (like parser xml). I mean from a String like this
String javaToParse = "public class x{void foo(){...} void baar(){...}}"
I could for example get the body (in string format) from foo or the body of all methods etc..
I have some like that
public class Some {
#PostConstruct
public void init1() {
//some to do
}
#PostConstruct
public void init2() {
//some to do2
}
#PostConstruct
public void init3() {
//some to do3
}
//..more..
}
Here there are one or more #PostConstruct
This class is autogenerated and I cannot modified it manually.
I would like to iterate all #PostConstruct methods and put all his bodies into only one #Postcontruct method and export to file and get this:
public class Some {
#PostConstruct
public void init() {
//some to do
//some to do2
//some to do3
}
}
I see that it's possible to do this getting that file as String and operate manually with fors and search manually but maybe there are librearies to do it.
EDIT:
Resolved with JavaParser
If somebody has similar problem here my solution:
public static void createUniquePostContruct(File InputFile,File outputFile) throws FileNotFoundException {
//get class to modified
FileInputStream in = new FileInputStream(ficheroEntradaJava);
// parse the file
CompilationUnit cu = JavaParser.parse(in);
//store methods with #PostContruct
List<MethodDeclaration> methodsPost = new ArrayList<>();
//iterate over all class' methods
cu.accept(new VoidVisitorAdapter<Void>() {
#Override
public void visit(MethodDeclaration method, Void arg) {
//if this method has #PostConstruct
if (method.getAnnotationByName("PostConstruct").isPresent()) {
methodsPost .add(method);
}
}
}, null);
//delete all methods with #PostConstruct
methodsPost.forEach((method) -> method.remove());
//add a unique #PostConstruct method using body of anothers #PostConstruct methods
MethodDeclaration uniqueMethodPostConstruct = new MethodDeclaration(EnumSet.of(Modifier.PUBLIC), new VoidType(), "init");
uniqueMethodPostConstruct.addAnnotation("PostConstruct");
BlockStmt bodyUniqueMethodPostConstruct= new BlockStmt();
metodosPost.forEach(method-> {
method.getBody().get().getStatements().forEach(statement -> {
bodyUniqueMethodPostConstruct.addStatement(statement);
});
});
metodoUnicoPostConstruct.setBody(bodyUniqueMethodPostConstruct);
//get main class and put our method
Optional<ClassOrInterfaceDeclaration> clazz = cu.getClassByName(ficheroEntradaJava.getName().split("\\.")[0]);
clazz.get().addMember(uniqueMethodPostConstruct);
System.out.println(cu.toString());
//write to file
try (PrintWriter out = new PrintWriter(outputFile)) {
out.println(cu.toString());
} catch (FileNotFoundException ex) {
Logger.getLogger(ParserMetodos.class.getName()).log(Level.SEVERE, null, ex);
}
}
I need to pass a string from class to another class in Java (Bukkit), I have already read some similar questions, but I can't solve the problem.
I have a Main class
public class Main extends JavaPlugin {
#Override
public void onEnable() {
new PlayerListener(this);
this.saveDefaultConfig();
String bannedBlocksString = this.getConfig().getString("bannedBlocks");
}
#Override
public void onDisable() {
}
}
And another class "PlayerListener"
public class PlayerListener implements Listener {
public PlayerListener(Main plugin) {
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
// public static final String bannedBlocksString = "DIAMOND_BLOCK; EMERALD_BLOCK";
public static final String[] bannedBlocks = bannedBlocksString.split("; ");
public static boolean isBannedBlock(String[] bannedBlocks, String blockPlaced) {
boolean returnValue = false;
for (String bannedBlock : bannedBlocks) {
if(blockPlaced.equalsIgnoreCase(bannedBlock)){
returnValue = true;
}
}
return returnValue;
}
#EventHandler
public void onBlockPlace(BlockPlaceEvent event) {
String blockPlaced = event.getBlockPlaced().getType().toString();
if(!event.getPlayer().hasPermission("antibuild.block.noplace") && isBannedBlock(bannedBlocks, blockPlaced)) {
event.setCancelled(true);
event.getPlayer().sendMessage(ChatColor.RED + "You can not place this block.");
}
}
}
How can I get the value of bannedBlocksString in Main from the class "PlayerListener"?
Try this, I hope it works:
From Main:
PlayerListener pl = new PlayerListener(this);
this.saveDefaultConfig();
String [] bannedBlocksString = pl.getBannedBlocks();
From PlayerListener you have to declare get method:
public String [] getBannedBlocks(){
return this.bannedBlocks;
}
If you uncomment the bannedBlocksString in the PlayerListener then you can always access it in the Main class using PlayerListener.bannedBlocksString as the variable is static.
If you want to do it the other way arround and assign the value you need to remove the final from the variable and use the code beneath.
PlayerListener.bannedBlocks = bannedBlocksString.split("; ");
I am trying to write really simple test with Mockito. I wrote small piece of code:
public class FlowTests {
#Mock
Calculator mockCalc = Mockito.mock(Calculator.class);
ConsoleView mockView = Mockito.mock(ConsoleView.class);
#Test
public void a01_Test() {
final String s = "2+2*2";
Controller c = new Controller();
c.setCalc(mockCalc);
Mockito.when(mockView.getFormule()).thenReturn(s); // I am not sure if it works
c.setView(mockView);
c.handle();
// TODO check if evaluate method has been invoked with "2+2*2"
}
}
Here you can see classes associated with this test:
public class Controller {
private IView view = new ConsoleView();
private ICalculator calc = new Calculator();
Double value = null;
public void handle() {
String formule = view.getFormule();
Double value = calc.evaluate(formule);
if (value != null) {
System.out.println("Result: ");
view.appendAnswer(value);
}
}
public void setCalc(ICalculator calc) {
this.calc = calc;
}
public void setView(IView view) {
this.view = view;
}
}
public class Calculator implements ICalculator {
public double evaluate(String s) {
...
char[] formuleChar = s.toCharArray();
result = calc.eval(formuleChar);
return result;
}
}
public class ConsoleView implements IView {
public String getFormule() {
... // getting s from console
return s;
}
public void appendAnswer(double r) {
System.out.println(r);
}
}
First goal of my test is to mock function getFormule() in ConsoleView to return always String s = "2+2*2". I did it but I am not sure if it works.
The main goal is to check if method evaluate() in Calculator class has been invoked with the same String. I have no idea how to that.
I cannot modify my code. I can only write a test.
Thank you in advance for your help!
Try something like this:
// check if evaluate method has been invoked with "2+2*2"
verify(mockCalc).evaluate("2+2*2");
Imagine the following situation, where an inherited method that calls a method of the superclass must call a method of the child class instead:
// super.java
public class Processor {
public void process(String path) {
File file = new File(path);
// some code
// ...
processFile(file);
}
protected void processFile(File file) {
// some code
// ...
reportAction(file.name());
}
protected void reportAction(String path) {
System.out.println("processing: " + path);
}
}
// child.java
public class BatchProcessor extends Processor {
public void process(String path) {
File folder = new File(path);
File[] contents = folder.listFiles();
int i;
// some code
// ...
for (i = 0; i < contents.length; i++) super.processFile(file);
}
protected void reportAction(String path) {
System.out.println("batch processing: " + path);
}
}
Obviously, the code presented above doesn't work as it should. The class BatchProcessor prints "processing: <file>" instead of "batch processing: <file>" as it calls the method from the superclass instead of the new one. Is there any way to overcome this obstacle?
Thanks in Advance! :D
Try this :
Processor processor = new Processor();
processor.process("filePath"); // will print "processing: <file>"
// and
Processor batchProcessor = new BatchProcessor();
batchProcessor.process("filePath"); // will print "batch processing: <file>"
this is how polymorphic methods work. I guess you are just not calling processor on subclass instance ?
edit
Please run the following code for a quick proof for yourself:
class Parent {
void test() {
subTest();
}
void subTest() {
System.out.println("subTest parent");
}
}
class Child extends Parent {
void subTest() {
System.out.println("subTest Child");
}
public static void main(String... args) {
new Child().test(); // prints "subTest Child"
}
}
Here is what happens when you call superClass processFile method on your subClass instance:
your this reference across this call will refer to your subClass instance, always resulting in polymorphic call of subClass's methods if they are overriden.
You can remove reportAction() from processFile() and call it separately if likely to change:
// super.java
public class Processor {
public void process(String path) {
File file = new File(path);
// some code
// ...
processFile(file);
reportAction(file.name());
}
protected void processFile(File file) {
// some code
// ...
}
protected void reportAction(String path) {
System.out.println("processing: " + path);
}
}
// child.java
public class BatchProcessor extends Processor {
public void process(String path) {
File folder = new File(path);
File[] contents = folder.listFiles();
int i;
// some code
// ...
for (i = 0; i < contents.length; i++)
{
super.processFile(file);
reportAction(file.name());
}
}
protected void reportAction(String path) {
System.out.println("batch processing: " + path);
}
}
The below is a simple java class file that checks if the file provided by the user is under the home directory or not. It throws an exception when the file is not under the home directory.
public class A {
public static void main(String args[]) {
if (new A().processArgs(args[0]) {
throw Exception("Not under home directory");
}
}
// A simple method to check if the file is at home directory
private boolean processArgs(String s) {
File f = new File(s);
String userHome = System.getProperty("user.home");
if (s.startsWith(userHome) && f.exists() && additionalLogic())
return true;
else
return false;
}
// Additional business Logic
private boolean additionalBusinessLogic() {
// Do wonderful things.
}
}
I want to write a simple Junit test case for testing the java class. Primary concern to test is the additional Business logic method. Is there a way I can bypass the check where directory must be under user home directory.
I am not comfortable in adding logic in my main class to make it aware of the Junit classes. Is there a better way to do this?
While there's nothing wrong with fab's solution, I decided to write another:
public class Main {
public static void main(String args[]) {
// TODO: Should check args length
Validator validator = new Validator();
validator.validateArgs(args[0]);
}
}
public interface Configuration {
public String getHomeDirectory();
}
public class DefaultConfiguration implements Configuration {
public String getHomeDirectory() {
String home = System.getProperty("user.home");
if (home == null) {
throw new RuntimeException("User home directory is not set!");
}
return home;
}
}
public class Validator {
private Configuration configuration;
public Validator() {
this(new DefaultConfiguration());
}
public Validator(Configuration configuration) {
this.configuration = configuration;
}
// A simple method to check if the file is at home directory
public void validateArgs(String s) {
File f = new File(s);
if (!s.startsWith(configuration.getHomeDirectory()) || !f.exists() || !additionalBusinessLogic())
throw new RuntimeException("Not under home directory!");
}
// Additional business Logic
private boolean additionalBusinessLogic() {
// TODO...
return true;
}
}
public class ValidatorTest {
#Test
public void validateValidArgsTest() {
final String homeDirectory = ".."; // TODO
String existingFile = homeDirectory + ".."; // TODO
new Validator(new Configuration() {
public String getHomeDirectory() {
return homeDirectory;
}
}).validateArgs(existingFile);
}
#Test(expected = RuntimeException.class)
public void validateInvalidArgsTest() {
String existingFile = ".."; // TODO
new Validator(new Configuration() {
public String getHomeDirectory() {
return "-INVALID PATH-";
}
}).validateArgs(existingFile);
}
}
You don't need to make the class aware of the test to make it more testable. You just need to decouple the additional logic from the i/o stuff, which will also result in a better design:
public class A {
private WonderfulThingsDoer wonderfulService;
public void main(String args[]) {
wonderfulService = new WonderfulThingsDoer();
if (processArgs(args[0]) {
throw Exception("Not under home directory");
}
}
// A simple method to check if the file is at home directory
private boolean processArgs(String s) {
File f = new File(s);
String userHome = System.getProperty("user.home");
if (s.startsWith(userHome) && f.exists() && additionalBusinessLogic())
return true;
else
return false;
}
// Additional business Logic
private boolean additionalBusinessLogic() {
return wonderfulService.doWonderfulThings();
}
}
public class WonderfulThingsDoer {
public boolean doWonderfulThings() {
// Do wonderful things.
return true;
}
}
Voilá, extracted a testable unit.
Simply don't hard code the "user.home"
Create a field home, that you change in the unit code, to point to the test directory:
public class A {
private static String homeDir;
protected static void setHomeDir(String home) {
this.homeDir = home;
}
public static void main(String args[]) {
if (homeDir == null) {
homeDir = System.getProperty("user.home");
}
A a = new A();
if (a.processArgs(args[0]) {
throw new InvalidArgumentException("Not under home directory");
}
}
// A simple method to check if the file is at home directory
protected boolean processArgs(String s) {
File f = new File(s);
if (s.startsWith(A.homeDir) && f.exists() && additionalLogic())
return true;
else
return false;
}
// Additional business Logic
private boolean additionalBusinessLogic() {
// Do wonderful things.
}
}
Now in the Unit Test, set the homeDir to your test directory
public void testMainHomeExisting() {
A a = new A;
String home = "./testdata/";
A.setHomeDir(home);
String[] args = new String[]{home}; // hope this compiles otherwise fix it
// no assert needed here, if test fails, an Exception is thrown
A.main(args);
}
Now a test case for home not existing
public void testMainHomeNotExisting() {
A a = new A;
String home = "./notExistingFooBarFooFoo/";
A.setHomeDir(home);
String[] args = new String[]{home}; // hope this compiles otherwise fix it
// no assert needed here, if test fails, an Exception is thrown
try {
A.main(args);
// if code works the next line should not be reached:
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException ex) {
// as expected got IllegalArgumentException
}
}
Just make a Test for the core business method additionalBusinessLogic only. You don't need to call main.
I see no reason to call main.
When you're writing a unit test, you want them to be modular enough to call without relying too much on external methods - and what you can't call you can mock, using something like EasyMock, PowerMock or Mockito.
I would change the method you want to test...
Remove the access modifier
Pass in the File variable you need to be able to do your logic
boolean additionalBusinessLogic(File f)
This will allow a test class in the same package to invoke the method. If you leave it private, no other classes will be able to call it.
Once you can call the method you want to test, the test class is easy...
public class MyClassTest {
#Test
public void additionalBusinessLogic_shouldFoo_whenSomeCondition() {
// setup
A a = new A();
File mockFile = mock(File.class);
// other setup stuff
// execute
boolean result = a.additionalBusinessLogic(mockFile);
// assert
// verify whatever you need to
}
}
For a good mocking framework, I would suggest Mockito.