Create Class from String and use Command Pattern - java

I know this has been questioned before on stackoverflow, but I could not find a solution for my problem.
I want to separate some Code from ButtonClick event, where I dynamically create Nodes on ButtonClick and add them to a parent AnchorPane. On my Nodes are Buttons, these Events on my Button are handled with a CommandPattern. I create different ButtonEvents, depending on the Node I created.
The Code which works fine so far is:
#FXML
void addErosionNode(ActionEvent event){
DragNode nde = new DragNode();
/*
id = nde.getId();
name = new String("Erosion");
Erosion cmd;
cmd = new Erosion();
nodeList.add(new NodeList<String, String, Command>(name, id, cmd));
*/
setupNode(nde);
nde.setNodeWithTwoCircles();
}
But I want to put the Code between /**/ inside another Method, so I can replace the Code with setupNode(nde, name);
And try to use this method:
public void setupNode(DragNode nde, String name){
id = nde.getId();
Class clazz;
className = new String ("application.bvfunc." + type);
//This will be e.g. application.bvfunc.Erosion which is the class I want to use
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException e) {
System.out.println("fail");
}
clazz cmd;
cmd = new clazz();
nodeList.add(new NodeList<String, String, Command>(name, id, cmd));
nde.nodeLayout();
rightAnchor.getChildren().add(nde);
buildDragHandlers();
}
But clazz cannot be resolved to a type.
How can I replace
Erosion cmd;
cmd = new Erosion();
with clazz I create with the name of my Node?
Like this:
clazz cmd;
cmd = new clazz();

You can, instead of using reflection, create a map that maps the names of their commands to the constructors:
private static final Map<String, Supplier<Command>> commandMap = new HashMap<>();
static {
commandMap.put("Erosion", Erosion::new);
commandMap.put("Dilation", Dilation::new);
}
Then in your other code:
public void setupNode(DragNode nde, String name){
id = nde.getId();
Command cmd = commandMap.get(name).get(); // <-- Calls the constructor
nodeList.add(new NodeList<String, String, Command>(name, id, cmd));
nde.nodeLayout();
rightAnchor.getChildren().add(nde);
buildDragHandlers();
}

Replace
clazz cmd;
cmd = new clazz();
with
Command cmd = (Command) clazz.newInstance();

Related

How to test function which calls another void function from it with static value as argument using mockito

I have a class A as
Class A{
private static final String ANON_DIR = "/webapps/worldlingo/data/anonymizer/";
private static final String NO_ANON = "noanonymize";
public String first(String text, String srclang, Map dictTokens) {
Set<String> noAnonymize = new HashSet<String>();
second(noAnonymize,ANON_DIR + NO_ANON, "tmpLang","name");
String value;
if(noAnonymize.contains("test")){
value = word;
}
else {
value = "test";
}
return value;
}
where ANON_DIR and NO_ANON is static final value. This class has function first and function second .The first function has a calling method in it which calls second function. The second function is void function which takes static fields as parameter.
Second function is just the file read function with the path provided as
private void second (Set<String> hashSet, String path, String lang , String type) {
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader(path);
br = new BufferedReader(fr);
String Line;
while ((Line = br.readLine()) != null) {
hashSet.add(Line);
}
} catch (IOException e) {
log.error("Anonymizer: Unable to load file.", e);
} finally {
try {
if (fr != null) {
fr.close();
}
if (br != null) {
br.close();
}
} catch (IOException e) {
log.error("Anonymizer : An error occured while closing a resource.", e);
}
}
}
}
Now I am trying to test the function first using mockito. I am trying to change the static parameter and send those changed static parameter as
public void testfirst() throws Exception {
A anon = new A();
Field ANON_DIR = A.class.getDeclaredField("ANON_DIR");
ANON_DIR.setAccessible(true);
//java relection to change private static final field
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(ANON_DIR, ANON_DIR.getModifiers() & ~Modifier.FINAL);
ANON_DIR.set(null,"test");
Field NO_ANON = A.class.getDeclaredField("NO_ANON");
NO_ANON.setAccessible(true);
Field modifiersField1 = Field.class.getDeclaredField("modifiers");
modifiersField1.setAccessible(true);
modifiersField1.setInt(NO_ANON, NO_ANON.getModifiers() & ~Modifier.FINAL);
NO_ANON.set(null,"/noanonymize");
Method anonymizeNames = anon.getClass().getDeclaredMethod("first", String.class, String.class , Map.class);
String srcLang = "MSFT_EN";
Map mapTokens = new HashMap();
String result = (String) anonymizeNames.invoke(anon,"I am David",srcLang,mapTokens);
}
PROBLEM:
Here I could change the private final static field ANON_DIR and NO_ANON using java reflection but the changed field are not send to the second function. The second function called from first function takes the original value instead of changed value. i.e when the second is called ANON_DIR has
"/webapps/worldlingo/data/anonymizer/" value instead of "test".
Since I changed the value of ANON_DIR to "test" I want the same "test" value to be passed to the second function. How can I acheive this for testing for void second method.
The problem here is the violation of the Separation of concerns principle.
Your code under test (cut) does too much and thus you have a hard time to find seams to replace dependencies.
Also there is a misunderstanding of the aim of unittests. You don't test code, you test public observable behavior which is any return value and communication with dependencies (but not necessarily public methods).
So my suggestion is to move method second() to a new class of its own. The cut gets an instance of this new class passed in as constructor parameter.
Then it is easy to replace the real dependency with a mock of that new class in your test.
On the other hand you could simple surrender to your bad design by using PowerMock...

Using a string to instantiate a class

Suppose I have classes Circle, Rectangle, and Triangle.
Based on input from a data file, I want to create the appropriate object. For instance, if the first line of shapes.dat is C.5 0 0, I will create a Circle object with radius 5. If the next line is R.5 3 0, I will create a Rectangle object with length 5 and width 3.
I know I could use basic if-else logic, but I was wondering whether there's a way to use the string as a means of instantiating a new object. Sort of like the exec() method in Python. Here's the code snippet describing what I want:
Scanner file = new Scanner (new File("shapes.dat"));
String s;
Map<Character,String> dict = new HashMap<Character,String>();
dict.put('C', "Circle");
dict.put('R', "Rectangle");
dict.put('T', "Triangle");
while (file.hasNextLine())
{
s = file.nextLine().trim();
String name = dict.get(s.toCharArray()[0]);
String data = s.split(".")[1];
String code = name + " x = new " + name + "(data);";
SYS.exec(code); //???
...
}
I'm not sure I understand correctly, seems weird no one else mentioned this yet:
Map<Character, ShapeFactory> dict = new HashMap<>();
dict.put('C', new CircleFactory());
dict.put('R', new RectangleFactory());
dict.put('T', new TriangleFactory());
...
ShapeFactory factory = dict.get(symbol);
Shape shape = factory.create(data);
You can make use of reflection to create instance dynamically.
String className = "com.shape.Triangle";
Class classDefinition = Class.forName(className);
Object obj = classDefinition.newInstance();
Or
Just use if-else to create instance of specific class.
Exec in Python executes code.
You can do the same thing with Java, for example with javassist.
You could read the data file, compile the statements and insert them in your own class.
But it seems overkill.
You could also use java reflection but it will produce a brittle and unclear code.
Instead if else if, I think that you should use abstraction and create a factory class by type of object.
It could look like :
Scanner file = new Scanner (new File("shapes.dat"));
String s;
Map<Character, ShapeBuilder> dict = new HashMap<Character,String>();
dict.put('C', new CircleBuilder());
dict.put('R', new RectangleBuilder());
dict.put('T', new TriangleBuilder());
while (file.hasNextLine()){
s = file.nextLine().trim();
char shapeSymbol = ...; // computed from s
ShapeBuilder builder = dict.get(shapeSymbol);
Shape shape = builder.build(s);
}
You can actually use polymorphism to avoid if-else statements. So, you can create objects that actually do those two jobs you want, match a line and create a shape. So you could use something like the following code.
public class Program {
public static void main() throws FileNotFoundException {
Scanner file = new Scanner(new File("shapes.dat"));
while (file.hasNextLine()) {
String line = file.nextLine().trim();
Shape shape = new Matches(
new RectangleMatch(),
new TriangleMatch(),
new SquareMatch(),
new CircleMatch()
).map(line);
}
}
public interface ShapeMatch {
boolean matches(String line);
Shape shape(String line);
}
public static final class RectangleMatch implements ShapeMatch {
#Override
public boolean matches(String line) {
return line.startsWith("R");
}
#Override
public Shape shape(String line) {
String[] dimensions = line.substring(2).split(" ");
return new Rectangle(
Integer.parseInt(dimensions[0]),
Integer.parseInt(dimensions[1]),
Integer.parseInt(dimensions[2])
);
}
}
public static final class CircleMatch implements ShapeMatch {
#Override
public boolean matches(String line) {
return line.startsWith("C");
}
#Override
public Shape shape(String line) {
return new Circle(Integer.parseInt(line.substring(2, line.indexOf(" "))));
}
}
public interface ShapeMapping {
Shape map(String line);
}
public static final class Matches implements ShapeMapping {
private final Iterable<ShapeMatch> matches;
public Matches(ShapeMatch... matches) {
this(Arrays.asList(matches));
}
public Matches(Iterable<ShapeMatch> matches) {
this.matches = matches;
}
#Override
public Shape map(String line) {
for (ShapeMatch match : matches) {
if (match.matches(line)) {
return match.shape(line);
}
}
throw new RuntimeException("Invalid shape entry line.");
}
}
}

Comparing a String to an Object's toString() method dynamically

I'm reading from a text file, like so:
while ((line = br.readLine()) != null) {
String[] a = line.split("\\: ");
key = a[0];
action = a[1];
gameKeys.add(key, action);
}
where the file would be something like
SPACE: FIRE_ACTION
E: USE_ACTION
This part works, key and action are both what I want.
gameKeys is a Map declared like so:
private static Map<Keyboard.Key, Action> gameKeys = new HashMap<>();
Keyboard.Key has fields such as SPACE, A, RETURN, etc.
Action is an interface, that holds other actions; those actions have a toString() method that returns the action, e.g. new FireAction.toString() returns FIRE_ACTION.
Example of an Action:
public class FireAction implements Action {
#Override
public void execute() {
System.out.println("Fire key pressed!");
}
#Override
public String toString() {
return "FIRE_ACTION";
}
}
So, I'm trying to turn the file's components into objects, like if key was "SPACE" and action was "FIRE_ACTION", then, after the add method is performed, gameKeys would have <Keyboard.Key.SPACE, new FireAction()>
Is there anyway I can do this?
You could try this:
Save your Action classes in a Map<String, Class<? extends Action>>
Read the Key -> Action bindings from the file
Resolve the string action to an actual Action object via the map
Example:
public class Main {
private static final Map<Keyboard.Key, Action> gameKeys = new HashMap<>();
private static final Map<String, Class<? extends Action>> actions = new HashMap<>();
static {
actions.put(FireAction.NAME, FireAction.class);
actions.put(WalkAction.NAME, WalkAction.class);
}
public static void main(String[] args) {
// read from file etc.
try {
// e.g. found SPACE : FIRE_ACTION
gameKeys.put(Keyboard.Key.SPACE, actions.get("FIRE_ACTION").newInstance());
// e.g. found A : WALK_ACTION
gameKeys.put(Keyboard.Key.A, actions.get("WALK_ACTION").newInstance());
} catch (IllegalAccessException | InstantiationException ex) {
ex.printStackTrace();
}
}
}
public class FireAction implements Action {
public static final String NAME = "FIRE_ACTION";
#Override
public void execute() {
System.out.println("Fire key pressed!");
}
#Override
public String toString() {
return NAME;
}
}
Sure
Object keyObj = key, actionObj;
if (key.equals("SPACE")) keyObj = Keyboard.Key.SPACE;
if (action.equals("FIRE_ACTION")) actionObj = new FireAction());
You can use a Map<String, ...> as an alternative to using 'if's if you have a lot of cases
You can't achieve what you have asked directly - because then Java would have to create ALL the classes it can create(some have non-default constructors or even private), and call their toString() method (which may have side-effects in general case).
So anyway you'll have to create registry with all actions(preferrable way), or you can try to use reflection to create Actions in runtime.

Not able to set value of instance variable of a class in Java while testing with JUnit

I am trying to test my classes using JUnits and i am facing an issue below is code.
There is a base class BaseMapper and TokenFraming which is dependent class.
The getMappedValue() from the baseclass is calling the mapStates() in the derived class.
I want to set the lineTokenizer instance variable in the TokenFraming class but it is not being set from the code.
When i debug TokenFraming the lineTokenizer is always Null and i get a Null Pointer exception when i try to access the tokenize() method.
I tried setting the value of lineTokenizer by using the setLineTokenizer() but still its not getting set. Also tried to set the value using Reflection but that also does not work. Any ideas as to what i am doing wrong here and how i can correct it. any help would be great.
Class BaseMapper {
private String fieldName;
private String fieldvalue;
// getters and setters
public static String getMappedValue(){
TokenFraming frame = new TokenFraming();
frame.mapStates(fieldName,fieldName,"validate")
}
}
Class TokenFraming {
private Tokenizer lineTokenizer = null;
public void setLineTokenizer(LineTokenizer arg) {
this.lineTokenizer = arg;
}
public String mapStates(String fieldName, String fieldName, String line) {
FieldMappedRow values = this.lineTokenizer.tokenize(line);// NullPointerException here
.......
.......
}
}
JUNit method
#Test
public void testMethods() {
TokenFraming framing = null;
try {
//using reflection to set is not working
framing = new TokenFraming();
Class<?> c1 = framing.getClass();
Field config = c1.getDeclaredField("lineTokenizer ");
config.setAccessible(true);
config.set(framing, new DefaulltToknizer());
//setting with a setter is also not working
framing.setLineTokenizer(new DefaulltToknizer());
BaseMapper mapped = new BaseMapper();
String value = mapped.getMappedValue();
} catch (Exception e) {
message = e.getMessage();
}
Assert.assertNotSame(null, message);
}
The BaseMapper class creates a new instance of TokenFraming - this is not the same instance of TokenFraming that you create in your test.
You should pass the TokenFraming object as an argument:
public static String getMappedValue(TokenFraming frame) {
frame.mapStates(fieldName,fieldName,"validate");
}

how to pass object parameters in command?

I created an eclipse-rcp's project's plugin.xml with a new command with a parameter.
ArrayList<parameterization> parameters = new ArrayList<parameterization>();
IParameter iparam;
//get the command from plugin.xml
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
ICommandService cmdService = (ICommandService)window.getService(ICommandService.class);
Command cmd = cmdService.getCommand("org.ipiel.demo.commands.click");
//get the parameter
iparam = cmd.getParameter("org.ipiel.demo.commands.click.paramenter1");
Parameterization params = new Parameterization(iparam, "commandValue");
parameters.add(params);
//build the parameterized command
ParameterizedCommand pc = new ParameterizedCommand(cmd, parameters.toArray(new Parameterization[parameters.size()]));
//execute the command
IHandlerService handlerService = (IHandlerService)window.getService(IHandlerService.class);
handlerService.executeCommand(pc, null);
I tried this example to pass parameters and it worked.
The issue in this example that I could pass only parameters of type String. ( because Parameterization )
I want to pass parameter of hash map and in general to pass any object.
I tried this code
IServiceLocator serviceLocator = PlatformUI.getWorkbench();
ICommandService commandService = (ICommandService) serviceLocator.getService(ICommandService.class);
ExecutionEvent executionEvent = new ExecutionEvent(cmd, paramArray, null, null);
cmd.executeWithChecks(executionEvent);
but it didn't work the parameters didn't move ( it was null)
Could you please help to to move object as parameter in command ?
Since it would get confusing to add another solution to my first answer, I'll provide another one for a second solution.
The choices I gave were " A) use the selected object of the "Execution Event" (examine that, it contains a lot of infos). B) you can use AbstractSourceProvider, so you can pass your object to the application context."
A) can be used in your Handler if your object is the selection of a Structured Object like a Tree:
MyObject p = (MyObject) ((IStructuredSelection) HandlerUtil.getCurrentSelection(event)).getFirstElement();
B) The usage of a Source provider is a bit more tricky. The main idea is, that you add your object to the application context. The important snippets for Eclipse 3.x from a project that I set up after I read this blog (note: it is in german and the example it provides doesn't work):
In your plugin.xml add:
<extension point="org.eclipse.ui.services">
<sourceProvider
provider="com.voo.example.sourceprovider.PersonSourceProvider">
<variable
name="com.voo.example.sourceprovider.currentPerson"
priorityLevel="activePartId">
</variable>
</sourceProvider>
Set up your own SourceProvider. Calling the "getCurrentState" you can get the variable (your Person object in this case) of that SourceProvider:
public class PersonSourceProvider extends AbstractSourceProvider{
/** This is the variable that is used as reference to the SourceProvider
*/
public static final String PERSON_ID = "com.voo.example.sourceprovider.currentPerson";
private Person currentPerson;
public PersonSourceProvider() {
}
#Override
public void dispose() {
currentPerson = null;
}
**/**
* Used to get the Status of the source from the framework
*/
#Override
public Map<String, Person> getCurrentState() {
Map<String, Person> personMap = new HashMap<String, Person>();
personMap.put(PERSON_ID, currentPerson);
return personMap;
}**
#Override
public String[] getProvidedSourceNames() {
return new String[]{PERSON_ID};
}
public void personChanged(Person p){
if (this.currentPerson != null && this.currentPerson.equals(p)){
return;
}
this.currentPerson = p;
fireSourceChanged(ISources.ACTIVE_PART_ID, PERSON_ID, this.currentPerson);
}
}
In your View you register to the SourceProvider and set the Object to the object you want to transfer to your Handler.
public void createPartControl(Composite parent) {
viewer = new TreeViewer(parent);
viewer.setLabelProvider(new ViewLabelProvider());
viewer.setContentProvider(new ViewContentProvider());
viewer.setInput(rootPerson);
getSite().setSelectionProvider(viewer);
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
#Override
public void selectionChanged(SelectionChangedEvent event) {
Person p = null;
if (event.getSelection() instanceof TreeSelection) {
TreeSelection selection = (TreeSelection) event.getSelection();
if (selection.getFirstElement() instanceof Person) {
p = (Person) selection.getFirstElement();
}
}
if (p==null) {
return;
}
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
ISourceProviderService service = (ISourceProviderService) window.getService(ISourceProviderService.class);
PersonSourceProvider sourceProvider = (PersonSourceProvider) service.getSourceProvider(PersonSourceProvider.PERSON_ID);
sourceProvider.personChanged(p);
}
});
}
And in your Handler you can just call the PersonSourceProvider#getCurrentState to get your Objects back.
Advantage of this method is, that you can use the Objectd anywhere you want. E.g. you can even set up a PropertyTester to enable/disable UI elements according to the currently selected Object.
The Parameterized Command does only accept Strings.
Here is an example for smaller objects:
Disclaimer: this is for Eclipse 3.x. I am not using Eclipse 4.x a lot, so you might have to adapt there in case you need it.
Create a Pluginproject (com.voo.example.commandparameter.advanced) with a View (com.voo.example.commandparameter.advanced.view) , a Command (com.voo.example.commandparameter.advanced.sysoCommand) with menu entry and Handler(com.voo.example.commandparameter.advanced.sysoCommand), and a universal Object (MyTestObject).
The Command needs a Parameter and a Parametertype in the plugin.xml, that gets passed to it:
<extension
point="org.eclipse.ui.commands">
<command
id="com.voo.example.commandparameter.advanced.sysoCommand"
name="SysoCommand">
<commandParameter
id="myObject"
name="object"
optional="true"
typeId="com.voo.example.commandparameter.advanced.testType">
</commandParameter>
</command>
<commandParameterType
id="com.voo.example.commandparameter.advanced.testType"
type="com.voo.example.commandparameter.advanced.MyTestObject">
</commandParameterType>
In the Object you set atrtibutes like name and street and define a convertToString method like that:
public String convertToString() {
return getName() +",,,"+ getStreet();
}
(you can override the toString method, too. I just used that method to set weired delimiters to the returned String)
And in a Class MyParamterConverter you can transfer it back:
public class MyParameterConverter extends AbstractParameterValueConverter {
public MyParameterConverter() {
}
#Override
public String convertToString(Object parameterValue)
throws ParameterValueConversionException {
return parameterValue.toString();
}
/**
* This will always create a new object. Just keep that in mind
* if you're trying to work with the objects.
*/
#Override
public Object convertToObject(String parameterValue)
throws ParameterValueConversionException {
//Split the String to get the attributes back
String delimiter =",,,";
String[] split = parameterValue.split(delimiter);
String name = split[0];
String street = split [1];
return new MyTestObject(name, street);
}
}
Now you can call the command with a buttonclick in your view, for example:
btnGo.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent event) {
MyTestObject testObject = new MyTestObject(textName.getText(),textStreet.getText());
ICommandService cS = (ICommandService)getSite().getService(ICommandService.class);
IHandlerService hS = (IHandlerService)getSite().getService(IHandlerService.class);
Command sysoComm = cS.getCommand("com.voo.example.commandparameter.advanced.sysoCommand");
HashMap<String, String> params = new HashMap<String, String>();
params.put("myObject", testObject.convertToString());
ParameterizedCommand pC = ParameterizedCommand.generateCommand(sysoComm, params);
try {
hS.executeCommand(pC, null);
} catch (Exception e) {
e.printStackTrace();
}
}
});
And the Handler can transform the passed parameters back :
public class MyObjectHandler extends AbstractHandler {
#Override
public Object execute(ExecutionEvent event) throws ExecutionException {
String param1 = event.getParameter("myObject");
MyParameterConverter converter = new MyParameterConverter();
Object convertToObject = null;
try {
convertToObject = converter.convertToObject(param1);
} catch (ParameterValueConversionException e) {
e.printStackTrace();
}
if (convertToObject instanceof MyTestObject) {
MyTestObject to = (MyTestObject) convertToObject;
System.out.println(to.toString());
}
return null;
}
}
This should work for most smaller sized objects that do not change while you pass them. If you need to pass bigger objects, you will have two choices: A) use the selected object of the "Execution Event" (examine that, it contains a lot of infos). B) you can use AbstractSourceProvider, so you can pass your object to the application context.
For a long time I have been focused on delivering an object via a command parameter. But in the end, the easiest workaround is to simply ignore the parameter stuff and put the desired object in a new child IExclipseContext and execute the command with that context. That way your handler gets your object injected.
Caller:
ECommandService commandService = // get commandService...
EHandlerService handlerService = // get handlerService...
IEclipseContext context = // get active or application context...
IEclipseContext childCtx = context.createChild();
childCtx.set(MyObject.class, instancOfMyObject);
ParameterizedCommand command = commandService.createCommand("my.command.id", null);
handlerService.executeHandler(command, childCtx);
In your handler:
#Execute
public void execute(#Optional MyObject myObject) {
if(myObject != null) {
// work with your object
}
}
Voila, no converters or callbacks (i.e. SelectionService) needed...
I am not really familiar with this as passing parameters to commands is quite rare. It looks like you have to use commandParameterType in the org.eclipse.ui.commands command definition to define code based on AbstractParameterValueConverter to convert between objects and the string for the parameter value.

Categories

Resources