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.
Related
Given the following code:
String s = "dirty";
for (Action action : actions) {
s = doAction(s, action);
}
...where Actions can be a cleaning operation on the string such as removing illegal chars or removing a duplicate word.
Is there a way to write this more elegantly to handle the call without reassigning the string?
I don't think you can avoid reassigning the string as you need the updated value in each iteration.
As for:
Is there a way to write this more elegantly
Using the streams API, you could do:
String result = actions.stream() // or Arrays.stream(actions)
.reduce("dirty", (s, action ) -> doAction(s, action),
(e, a) -> {throw new RuntimeException("un-implemented");});
Although it's arguably not as readable as your solution.
A recursive way to write it would be something like this:
public static void main(String[] args) {
List<Action> actions = .. //your list of Actions
String s = doActions("dirty", actions);
}
private static String doActions(String s, List<Action> actions) {
if(actions.isEmpty()) {
return s;
} else {
// apply the first Action
Action action = actions.remove(0);
String newString = doAction(s, action);
// recursively call with the new String and the remaining actions
return doActions(newString, actions);
}
}
But as you can see, you still get a string creation/assignement in the doActions method. This is due to the fact that String is immutable and can't be modified.
If you are just looking for a recursive way to write it then that could do. If you really want to get rid of the new String creation, you need to use a StringBuilder, as Jacob G suggested. With a signature such as
void doAction(StringBuilder sb, Action action)
You can avoid reassigning s by making it a field
public class SActions {
private String s;
SActions(String s){this.s = s;}
public void doAction(Action action){ /* apply action to s */}
public String getString() { return s; }
public static void main(String[] args) {
SActions sActions = new SActions("abc");
sActions.doAction(anAction);
System.out.println(sActions.getString());
}
}
You could also add a method to accept a collection of Actions:
public void doAction(Collection<Action> actions) {
for (Action action : actions) {
doAction(action);
}
}
To make the object reusable, add a setter:
public SActions setString(String s) {
this.s = s;
return this;//for convenience, so you can chain invocation
}
Note that the setter return this for more convenient invocation:
SActions sActions = new SActions(); //requiers standard constructor
sActions.setString("abc").doAction(anAction);
If it is more or less elegant' it is certainly arguable.
I need to do a lot of different preprocessing of some text data, the preprocessing consists of several simple regex functions all written in class Filters that all take in a String and returns the formatted String. Up until now, in the different classes that needed some preprocessing, I created a new function where I had a bunch of calls to Filters, they would look something like this:
private static String filter(String text) {
text = Filters.removeURL(text);
text = Filters.removeEmoticons(text);
text = Filters.removeRepeatedWhitespace(text);
....
return text;
}
Since this is very repetitive (I would call about 90% same functions, but 2-3 would be different for each class), I wonder if there are some better ways of doing this, in Python you can for example put function in a list and iterate over that, calling each function, I realize this is not possible in Java, so what is the best way of doing this in Java?
I was thinking of maybe defining an enum with a value for each function and then call a main function in Filters with array of enums with the functions I want to run, something like this:
enum Filter {
REMOVE_URL, REMOVE_EMOTICONS, REMOVE_REPEATED_WHITESPACE
}
public static String filter(String text, Filter... filters) {
for(Filter filter: filters) {
switch (filter) {
case REMOVE_URL:
text = removeURL(text);
break;
case REMOVE_EMOTICONS:
text = removeEmoticons(text);
break;
}
}
return text;
}
And then instead of defining functions like shown at the top, I could instead simply call:
filter("some text", Filter.REMOVE_URL, Filter.REMOVE_EMOTICONS, Filter.REMOVE_REPEATED_WHITESPACE);
Are there any better ways to go about this?
Given that you already implemented your Filters utility class you can easily define a list of filter functions
List<Function<String,String>> filterList = new ArrayList<>();
filterList.add(Filters::removeUrl);
filterList.add(Filters::removeRepeatedWhitespace);
...
and then evaluate:
String text = ...
for (Function<String,String> f : filterList)
text = f.apply(text);
A variation of this, even easier to handle:
Define
public static String filter(String text, Function<String,String>... filters)
{
for (Function<String,String> f : filters)
text = f.apply(text);
return text;
}
and then use
String text = ...
text = filter(text, Filters::removeUrl, Filters::removeRepeatedWhitespace);
You could do this in Java 8 pretty easily as #tobias_k said, but even without that you could do something like this:
public class FunctionExample {
public interface FilterFunction {
String apply(String text);
}
public static class RemoveSpaces implements FilterFunction {
public String apply(String text) {
return text.replaceAll("\\s+", "");
}
}
public static class LowerCase implements FilterFunction {
public String apply(String text) {
return text.toLowerCase();
}
}
static String filter(String text, FilterFunction...filters) {
for (FilterFunction fn : filters) {
text = fn.apply(text);
}
return text;
}
static FilterFunction LOWERCASE_FILTER = new LowerCase();
static FilterFunction REMOVE_SPACES_FILTER = new RemoveSpaces();
public static void main(String[] args) {
String s = "Some Text";
System.out.println(filter(s, LOWERCASE_FILTER, REMOVE_SPACES_FILTER));
}
}
Another way would be to add a method to your enum Filter and implement that method for each of the enum literals. This will also work with earlier versions of Java. This is closest to your current code, and has the effect that you have a defined number of possible filters.
enum Filter {
TRIM {
public String apply(String s) {
return s.trim();
}
},
UPPERCASE {
public String apply(String s) {
return s.toUpperCase();
}
};
public abstract String apply(String s);
}
public static String applyAll(String s, Filter... filters) {
for (Filter f : filters) {
s = f.apply(s);
}
return s;
}
public static void main(String[] args) {
String s = " Hello World ";
System.out.println(applyAll(s, Filter.TRIM, Filter.UPPERCASE));
}
However, if you are using Java 8 you can make your code much more flexible by just using a list of Function<String, String> instead. If you don't like writing Function<String, String> all the time, you could also define your own interface, extending it:
interface Filter extends Function<String, String> {}
You can then define those functions in different ways: With method references, single- and multi-line lambda expressions, anonymous classes, or construct them from other functions:
Filter TRIM = String::trim; // method reference
Filter UPPERCASE = s -> s.toUpperCase(); // one-line lambda
Filter DO_STUFF = (String s) -> { // multi-line lambda
// do more complex stuff
return s + s;
};
Filter MORE_STUFF = new Filter() { // anonymous inner class
// in case you need internal state
public String apply(String s) {
// even more complex calculations
return s.replace("foo", "bar");
};
};
Function<String, String> TRIM_UPPER = TRIM.andThen(UPPERCASE); // chain functions
You can then pass those to the applyAll function just as the enums and apply them one after the other in a loop.
In my program, the user needs to input what type of players the game will have. The players are "human", "good" (for a good AI), "bad" (for a bad AI) and "random" (for a random AI). Each of these players have their own class that extend one abstract class called PlayerType.
My struggle is mapping a String to the object so I can A) create a new object using the String as sort of a key and B) get the related String from an object of its subclass
Ultimately, I just want the implicit String to only appear once in the code so I can change it later if needed without refactoring.
I've tried using just a plain HashMap, but that seems clunky with searching the keys via the values. Also, I'm guessing that I'll have to use the getInstance() method of Class, which is a little less clunky, which is okay if it's the only way.
What I would do is create an enum which essentially functions as a factory for the given type.
public enum PlayerTypes {
GOOD {
#Override
protected PlayerType newPlayer() {
return new GoodPlayer();
}
},
BAD {
#Override
protected PlayerType newPlayer() {
return new BadPlayer();
}
},
RANDOM {
#Override
protected PlayerType newPlayer() {
return new RandomPlayer();
}
};
protected abstract PlayerType newPlayer();
public static PlayerType create(String input) {
for(PlayerTypes player : PlayerTypes.values()) {
if(player.name().equalsIgnoreCase(input)) {
return player.newPlayer();
}
}
throw new IllegalArgumentException("Invalid player type [" + input + "]");
}
)
Because then you can just call it like so:
String input = getInput();
PlayerTypes.create(input);
Of course, you'll get an IllegalArgumentException which you should probably handle by trying to get the input again.
EDIT: Apparently in this particular case, you can replace that loop with just merely
return PlayerTypes.valueOf(input).newPlayer();
And it'll do the same thing. I tend to match for additional constructor parameters in the enum, so I didn't think of using valueOf(), but it's definitely cleaner.
EDIT2: Only way to get that information back is to define an abstract method in your PlayerType class that returns the PlayerTypes enum for that given type.
public class PlayerType {
public abstract PlayerTypes getType();
}
public class GoodPlayer extends PlayerType {
#Override
public PlayerTypes getType() {
return PlayerTypes.GOOD;
}
}
I like the answer provided by Epic but I don't find maps to be clunky. So it's possible to keep a map and get the constructor call directly.
Map<String, Supplier<PlayerType> map = new HashMap<>();
map.put("human", Human::new);
Human h = map.get("human").get();
The two main options I can think of:
Using Class.newInstance(), as you mentioned (not sure if you had this exact way in mind):
// Set up your map
Map<String, Class> classes = new HashMap<String, Class>();
classes.put("int", Integer.class);
classes.put("string", String.class);
// Get your data
Object s = classes.get("string").newInstance();
You could use Class.getDeclaredConstructor.newInstance if you want to use a constructor with arguments (example).
Another option is using switch:
Object getObject(String identifier) {
switch (identifier) {
case "string": return new String();
case "int": return new Integer(4);
}
return null; // or throw an exception or return a default object
}
One potential solution:
public class ForFunFactory {
private ForFunFactory() {
}
public static AThing getTheAppropriateThing(final String thingIdentifier) {
switch (thingIdentifier) {
case ThingImplApple.id:
return new ThingImplApple();
case ThingImplBanana.id:
return new ThingImplBanana();
default:
throw new RuntimeException("AThing with identifier "
+ thingIdentifier + " not found.");
}
}
}
public interface AThing {
void doStuff();
}
class ThingImplApple implements AThing {
static final String id = "Apple";
#Override
public void doStuff() {
System.out.println("I'm an Apple.");
}
}
class ThingImplBanana implements AThing {
static final String id = "Banana";
#Override
public void doStuff() {
System.out.println("I'm a Banana.");
}
}
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.
I have a Java application and I want to implement an Undo/Redo option. the value that I want to stock and that I want to be able to recover is an integer.
My Class Model implements the interface StateEditable and I have to redefine the 2 functions restoreState(Hashtable<?, ?> state) and storeState(Hashtable<Object, Object> state) but I don't know what to put on them. It will be really great if somebody can help me to do that.
These are the first lines of my Model class, the value that I want to do an undo/redo on it is value
public class Model extends Observable implements StateEditable
{
private int value = 5;
private UndoManager undoRedo = new UndoManager();
final UndoableEditListener editListener = new UndoableEditListener() {
public void undoableEditHappened(UndoableEditEvent evt) {
undoRedo.addEdit(evt.getEdit());
}
};
#Override
public void restoreState(Hashtable<?, ?> state)
{
}
#Override
public void storeState(Hashtable<Object, Object> state)
{
}
}
From looking through an example of StateEditable, it would appear that in your storeState method, you need to populate the Hashtable that is passed in. Similarly, you assign state in your restoreState from the Hashtable that is passed in. You will need to define a key for the value in the Hashtable. With that in mind, I suggest that you add
private final String KEY = "myKey";
to the top of your file, and then fill out the two methods like so:
#Override
public void restoreState(Hashtable<?, ?> state)
{
Object val = state.get(KEY);
if( val instanceof Integer ) //performs the null test for us.
{
value = val;
}
}
#Override
public void storeState(Hashtable<Object, Object> state)
{
state.put(KEY, value);
}