Freemarker ignore missing variables - java

I'm using freemarker to generate files and I'm struggling with the templateExeptionHandler part. I have variables in my template that don't have to be replaced (if they are not present in the data-model). I don't like to put these variables inside my data-model with the same value (can't get it to work either) and I know I can 'escape' variables in the template itself but I don't really like that solution.
MyTemplateExceptionHandler looks as follows:
class MyTemplateExceptionHandler implements TemplateExceptionHandler {
public void handleTemplateException(TemplateException te, Environment env, Writer out) throws TemplateException {
try {
out.write("${" + te.getBlamedExpressionString() + "}");
} catch (IOException e) {
throw new TemplateException("Failed to print error message. Cause: " + e, env);
}
}
}
The problem is that once I'm parsing variables in the form of:
${workflow.input.myVariable}
the result in my new generated file is showing only the first part of this variable:
${workflow}
Any thoughts on how I can get the full variable back and returned in my generated file?

That use case is not supported, as of 2.3.27 at least. It's not even clear how it should work, like, what if the missing variable is a parameter to a directive? Certainly it could be solved for the case of ${} only (even then, only when it appears outside a string literal), but I'm not sure if that addresses the need, or it just lures uses into using it and then they hit a wall later on with a directive parameter... (Or, another tricky case, what's with ${thisIsMissing + thisExists}? I guess it should become to something like ${thisIsMissing + 123}... so doing this right can complicate the core quite much.)

Related

Is it possible to add a variable where code should be?

I am currently trying to create an automation framework using Java and Selenium.
I want to create a line of code which essentially can read any input and make it a line of runnable code. For example, in an external file, a user could post 'id' into a field, that field will then be read by my program and execute the line. driver.findElement(By.id(.......)
Currently I'm using a bunch of if statements to do this for each identifier e.g. id, cssSelector, Xpath etc etc but then I'll need to do the same for the actions used by the program .click, .sendKeys etc so the program will just keep expanding and look overall very messy.
Is there a solution that would allow me to do this in a nicer way or am I stuck with my original approach?
Reflection is probably the most direct way to solve this. It essentially allows classes and methods to be looked up by their string names.
Here's a fag-packet example of how you might approach this using the snippet you provided, but I suggest you read some documentation before diving in.
Element findElementReflectively(Driver driver, String elementType, String thingToSearchFor) {
try {
Method m = By.class.getMethod(elementType, String.class);
if(!Modifier.isStatic(m.getModifiers())) {
throw new NoSuchMethodException("'By' method is not static.");
}
return driver.findElement(m.invoke(null, thingToSearchFor));
} catch (IllegalAccessException | NoSuchMethodException e) {
throw new IllegalArgumentException("Unknown element type: " + elementType, e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Failed to find requested element.", e.getCause());
}
}
It depends on what you actually want to do.
Reading an id from a file and then execute code can be achieved through config file with this : Properties
Or if you want to execute full input code just search a little bit more
How to execute console or GUI input as if it was actual Java code?

Iterate over certain subpaths in Path in Java

I am working with code which makes use of java.nio.file.Path. I have a path like
/tmp/something/first/second/third/last
which I see only as
{parent.dir}/first/second/third/{path.end}
In this example /tmp/something or {parent.dir} is a path which can be different during runtime and which is irrelevant for me. The same applies for the last element in the path {path.end}
What I would need is to iterate over elements between {parent.dir} and {path.end}. Basically to test each element in the path if it exists and if it is a file or
a directory or something else (it doesn't matter).
I am therefore looking for some elegant/simple and proper way to iterate over instance of Pathwhere I can access paths like these:
/tmp
/tmp/something/
/tmp/something/first
...
/tmp/something/first/second/third/last
ideally in this case without the first 2 and the last iteration.
I am looking for a good solution using Path and java.nio and not the old way. I know I can achieve this using old io API but I am interested in the proper way of using nio.
Here I print all directories child of your parent dir:
Files.walk(Paths.get(${parent.dir})).filter(path -> Files.isDirectory(path, LinkOption.NOFOLLOW_LINKS)).forEach(System.out::println);
You can pass another lambda to the forEach method for your own purpose.
Also replace ${parent.dir} with your correct value as a String.
(The code above may throw IOException).
Assuming that the base and end parts are parameters, while the in-between part is fixed, a solution can look like this:
static void iterate(Path base, Path end) {
if(!base.isAbsolute() || end.isAbsolute()) throw new
IllegalArgumentException("base must be absolute, end must be relative");
// test the fixed in-between paths
Path fixed=Paths.get("first", "second", "third");
for(Path part: fixed) {
base=base.resolve(part);
System.out.print(base);
if(Files.isDirectory(base)) {
System.out.println(" is a directory");
}
else {
System.out.println(Files.exists(part)?" is not a directory":" does not exist");
return;
}
}
// test the end path
end=base.resolve(end);
System.out.print(end+(
Files.isDirectory(end)? " is a directory":
Files.exists(end)? " is not a directory": " does not exist"));
}
It stops the iteration once it encounters a non-directory path component. You will have to adapt this behavior if you want to enforce a specific policy regarding following symbolic links…

Handling non-fatal errors in Java

I've written a program to aid the user in configuring 'mechs for a game. I'm dealing with loading the user's saved data. This data can (and some times does) become partially corrupt (either due to bugs on my side or due to changes in the game data/rules from upstream).
I need to be able to handle this corruption and load as much as possible. To be more specific, the contents of the save file are syntactically correct but semantically corrupt. I can safely parse the file and drop whatever entries that are not semantically OK.
Currently my data parser will just show a modal dialog with an appropriate warning message. However displaying the warning is not the job of the parser and I'm looking for a way of passing this information to the caller.
Some code to show approximately what is going on (in reality there is a bit more going on than this, but this highlights the problem):
class Parser{
public void parse(XMLNode aNode){
...
if(corrupted) {
JOptionPane.showMessageDialog(null, "Corrupted data found",
"error!", JOptionPane.WARNING_MESSAGE);
// Keep calm and carry on
}
}
}
class UserData{
static UserData loadFromFile(File aFile){
UserData data = new UserData();
Parser parser = new Parser();
XMLDoc doc = fromXml(aFile);
for(XMLNode entry : doc.allEntries()){
data.append(parser.parse(entry));
}
return data;
}
}
The thing here is that bar an IOException or a syntax error in the XML, loadFromFile will always succeed in loading something and this is the wanted behavior. Somehow I just need to pass the information of what (if anything) went wrong to the caller. I could return a Pair<UserData,String> but this doesn't look very pretty. Throwing an exception will not work in this case obviously.
Does any one have any ideas on how to solve this?
Depending on what you are trying to represent, you can use a class, like SQLWarning from the java.sql package. When you have a java.sql.Statement and call executeQuery you get a java.sql.ResultSet and you can then call getWarnings on the result set directly, or even on the statement itself.
You can use an enum, like RefUpdate.Result, from the JGit project. When you have a org.eclipse.jgit.api.Git you can create a FetchCommand, which will provide you with a FetchResult, which will provide you with a collection of TrackingRefUpdates, which will each contain a RefUpdate.Result enum, which can be one of:
FAST_FORWARD
FORCED
IO_FAILURE
LOCK_FAILURE
NEW
NO_CHANGE
NOT_ATTEMPTED
REJECTED
REJECTED_CURRENT_BRANCH
RENAMED
In your case, you could even use a boolean flag:
class UserData {
public boolean isCorrupt();
}
But since you mentioned there is a bit more than that going on in reality, it really depends on your model of "corrupt". However, you will probably have more options if you have a UserDataReader that you can instantiate, instead of a static utility method.

Parsing a string with multiple variations

I am curious as to what a better way to deal with this is, I wanted to challenge my self and see if I could break up, in a HashMap of key,value (or String, String), a string that could come back in almost any format.
the string in question is:
/user/2/update?updates=success
Thats right, a url request for a server. The issue - as we all know this could be any thing, it could come back in any form. I wanted to break it up so that it would look like:
Controller => user
action => update
params => ??? (theres a 2, a update=success ... )
Obviously The above is not a real java object.
But you get the idea.
What do you need? what have you done? what are you trying to do?
What I want to do is map this to a controller and action while passing in the parameters along the way. But i need to separate this up making sure to specify each step what is what.
What I have done is:
private Filter parseRoute(String route){
String[] parsedRoute = route.split("[?:/=]");
Filter filter = new Filter(parsedRoute);
return filter;
}
Splits on any thing that is in the url (note, : would be something like /user:id/update
so: user/2/update ... )
I then attempted to do:
public class Filter {
private HashMap<String, String> filterInfo;
public Filter(String[] filteredRoute){
if(filteredRoute.length > 0){
filterInfo.put("Controller", filteredRoute[0]);
}else{
throw new RoutingException("routes must not be empty.");
}
}
}
But this is not going to work as I expected it to...As there are too many variables at play.
including parameters before the action (those would just be used to search for that user), their could be nested routes, so multiple controller/action/controller/action ..
How would you deal with this? What would you suggest? How could you get around this? Should you just do something like:
route(controller, action, params, template); ? (template lets you render a jsp). if so how do you deal with the ?update=success
I am using HttpServer to set up the basics. But I am now lost. I am trying to keep routing as generic and "do what ever you want we will map it to the right controller, action and pass in the parameters" but I think I bit off more then I can chew.
I have looked at both spark and spring framework, and decided that the route you pass, we will map to a xml file to find the controller and action, I just need the data structure in place to do that ...
So I am looking to back up and still go with "pass me something, ill map it out."
I would probably use the URL from apache,
org.apache.tomcat.util.net.URL url = null;
try {
url = new org.apache.tomcat.util.net.URL("/user/2/update?updates=success");
// ... do some stuff with it...
} catch (Exception e) {
e.printStackTrace();
}
java.net.URI may help you.
you can get your path by getPath()
and get all of your query by getQuery(),then you can split the query by = to name value pairs.
URI uri = new URI("/user/2/update?updates=success");
// /user/2/update
System.out.println("path is " + uri.getPath());
// updates=success
System.out.println("query is " + uri.getQuery());

GWT Maven plugin: Generating non-String parameters in the Messages class

I have a property in my "Messages.properties" file that has an argument that uses number formatting:
my.message=File exceeds {0,number,0.0}MB.
When I run the gwt:i18n Maven goal, it generates a Messages interface based on the properties in my "Messages.properties" file (like normal):
public interface Messages extends com.google.gwt.i18n.client.Messages {
//...
#DefaultMessage("File exceeds {0,number,0.0}MB.")
#Key("my.message")
String my_message(String arg0);
//...
}
The problem is that the method parameter is a String. When I run the application, it gives me an error because the message argument expects a number, but a String is supplied (the error message is, "Only Number subclasses may be formatted as a number").
How do I configure Maven to have it change this parameter to number (like a float or Number)? Thanks.
Given the discussion above, I have decided to complement my previous answer.
First of all, as far as I know there's no way you can use the existing i18n Maven goal (and GWT's I18NCreator) to do what is asked.
Secondly, after researching a bit more on the Generator solution I had suggested, I found that:
Michael is right that you wouldn't pick up errors at compile time using the interface method with look up for properties (a sin in GWT) as suggested above. However, this is still the simplest/quickest way to do it.
You can ensure compile-time check by writing your own interface which
is kept up-to-date with the properties file, having one method for each property, and then getting your
generator to write a class which implements that interface. Notice
that when you change a property on the properties file, you only need
to change the interface you wrote. If you've written the Generator
properly, it will never have to be changed again! The best way to go
about method names is probably follow GWT: if a property is called
the.prop.one, then the method name is the_prop_one(..).
If you really don't want to maintain an interface manually, the only
way I can see is for you to write your own version of I18NCreator.
This is because the maven goal i18n is not a GWT compiler
parameter, but a call for the maven plugin to write
Messages/Constants interfaces based on properties files found in the
class path. Therefore, if you write your own I18NCreator, you will
have to also write a Maven plugin that you can use to call it before
compiling the GWT application. Or, to make it simpler, you can simply
run your I18NCreator manually (using the good-old java command to run
it) every time you change your properties file keys (of course,
there's no need to run it when only actual messages are changed).
Personally, I would just write and maintain my properties file and the interface that mirrors it manually. The Generator will always look at the properties file and generate the methods that correspond to the properties (with whatever arguments are required based on the actual message), so if the interface you wrote reflects the properties file, the class generated by the Generator will always implement it correctly.
It seems to me this feature is not supported by GWT I18NCreator (which is what the maven i18n goal calls). You would have to write your own Generator to do that.
I have written a couple of Generators and it's not as hard as you may think.
In your case, you would want to write a Generator that creates an instance of an interface similar to GWT's Messages (but you can use your own) but which has the added functionality that you want when decoding messages.
The following how-to little guide may help you, as it seems it's pretty much what I did as well and it works:
http://groups.google.com/group/Google-Web-Toolkit/msg/ae249ea67c2c3435?pli=1
I found that the easiest way to write a GWT Generator is to actually write a test class with the code you would want generated in your IDE (and with the help of auto-completion, syntax-checks etc), and then past/adapt it to the writer calls like this:
writer.println("public void doSomething() { /* implement */ }");
And don't forget to tell your module (module.gwt.xml file) which interface needs to be generated, and with which class, like this:
<generate-with class="mycompany.utils.generators.MyGenerator">
<when-type-assignable class="mycompany.messages.MyCoolPropertiesReader" />
</generate-with>
In the Generator code, you can use Java with all its great features (not limited to GWT-translatable code) so it shouldn't be hard to implement what you want. In the client-side code, you can then just do:
public interface MyCoolPropertiesReader {
public String getMessage(String propKey, Object... parameters);
}
public class MyClientSideClass {
MyCoolPropertiesReader reader = GWT.create(MyCoolPropertiesReader.class);
String msg = reader.getMessage("my.message", 10);
// do more work
}
A test Generator that I wrote (a GWT "reflective" getter and setter, as it were) looks like this:
public class TestGenerator extends Generator {
#Override
public String generate(TreeLogger logger, GeneratorContext context,
String typeName) throws UnableToCompleteException {
try {
TypeOracle oracle = context.getTypeOracle();
JClassType requestedClass = oracle.getType(typeName);
String packageName = requestedClass.getPackage().getName();
String simpleClassName = requestedClass.getSimpleSourceName();
String proxyClassName = simpleClassName + "GetterAndSetter";
String qualifiedProxyClassName = packageName + "." + proxyClassName;
System.out.println("Created a class called: " + qualifiedProxyClassName);
PrintWriter printWriter = context.tryCreate(logger, packageName, className);
if (printWriter == null) return null;
ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory(packageName, className);
composerFactory.addImport("test.project.shared.GetterAndSetter");
composerFactory.addImplementedInterface("GetterAndSetter<" + underlyingTypeName + ">");
SourceWriter writer = composerFactory.createSourceWriter(context, printWriter);
if (writer != null) {
JField[] fields = requestedClass.getFields();
for (JField field : fields) {
createSetterMethodForField(typeName, writer, field);
}
writer.indent();
writer.println("public void set(" + typeName + " target, String path, Object value) {");
writer.indent();
createIfBlockForFields(writer, fields, true);
writer.outdent();
writer.println("}");
writer.println();
writer.println("public <K> K get(" + typeName + " target, String path) {");
writer.indent();
createIfBlockForFields(writer, fields, false);
writer.outdent();
writer.println("}");
writer.println();
writer.outdent();
writer.commit(logger);
}
return packageName + "." + proxyClassName;
} catch(NotFoundException nfe) {
throw new UnableToCompleteException();
}
}
}
I hope this helps you.

Categories

Resources