We had a lot of strings which contained the same sub-string, from sentences about checking the log or how to contact support, to branding-like strings containing the company or product name. The repetition was causing a few issues for ourselves (primarily typos or copy/paste errors) but it also causes issues in that it increases the amount of text our translator has to translate.
The solution I came up with went something like this:
public class ExpandingResourceBundleControl extends ResourceBundle.Control {
public static final ResourceBundle.Control EXPANDING =
new ExpandingResourceBundleControl();
private ExpandingResourceBundleControl() { }
#Override
public ResourceBundle newBundle(String baseName, Locale locale, String format,
ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException, IOException {
ResourceBundle inner = super.newBundle(baseName, locale, format, loader, reload);
return inner == null ? null : new ExpandingResourceBundle(inner, loader);
}
}
ExpandingResourceBundle delegates to the real resource bundle but performs conversion of {{this.kind.of.thing}} to look up the key in the resources.
Every time you want to get one of these, you have to go:
ResourceBundle.getBundle("com/acme/app/Bundle", EXPANDING);
And this works fine -- for a while.
What eventually happens is that some new code (in our case autogenerated code which was spat out of Matisse) looks up the same resource bundle without specifying the custom control. This appears to be non-reproducible if you write a simple unit test which calls it with and then without, but it occurs when the application is run for real. Somehow the cache inside ResourceBundle ejects the good value and replaces it with the broken one. I am yet to figure out why and Sun's jar files were compiled without debug info so debugging it is a chore.
My questions:
Is there some way of globally setting the default ResourceBundle.Control that I might not be aware of? That would solve everything rather elegantly.
Is there some other way of handling this kind of thing elegantly, perhaps without tampering with the ResourceBundle classes at all?
I think this is a fundamental flaw in the way ResourceBundles are designed to function: keys that reference other keys automatically violate the DRY (don't repeat yourself) principle. The way I got around this was similar to your method: create a ReflectiveResourceBundle class that allows you to specify Resource keys in the messages using EL notation.
THE WRONG WAY:
my.name.first=Bob
my.name.last=Smith
my.name.full=Bob Smith
THE RIGHT WAY:
my.name.first=Bob
my.name.last=Smith
my.name.full=${my.name.first} ${my.name.last}
I've uploaded the code to GitHub so you or anyone else can download it. Additionally, I've added some sample code for anyone using the Stripes Framework (http://www.stripesframework.org/) to get you quickly up-and-running.
The trick to getting this to work with standard JSTL fmt taglibs was to set up an interceptor that replaced the HttpServletRequest's resource with our own. The code looks something like this:
ResourceBundle bundle = MyStaticResourceHoldingTheBundle.getBundle();
Config.set(request, Config.FMT_LOCALIZATION_CONTEXT, new LocalizationContext(bundle, locale));
Take a look at the stripes.interceptor package in the link above for more details.
If the string repetitions are localized in the sense that you know a certain string will be repeated but only within the same project such that sharing resource bundles is not a design nightmare, then you might consider breaking the strings down into multiple key-value parts. Separate the parts that repeat from those that do not and reuse the repeated parts. For example, lets say you have the following two strings you need to display:
"The Red-capped Robin is a small passerine bird native to Australia. "
"The Red-capped Robin is found in dryer regions across much of the continent."
The resource bundle could be as follows:
robin.name=The Red-capped Robin
robin.native=is a small passerine bird native to Australia.
robin.region=is found in dryer regions across much of the continent.
and then combine the required parts where needed bundle.getString("robin.name")+bundle.getString(robin.native).
One thing you need to be careful about though is that the grammar rules like subject predicate order etc. might not be the same in all languages. So you would need to be a little careful when splitting sentences.
Related
I'm stuck on this concept.
This is part of an explanation I saw on a site:
Hiding the Implementation
A primary consideration in object-oriented design is separating the things that change from the things that stay the same.
This is particularly important for libraries. Users (client programmers) of that library must be able to rely on the part they use, and know that they won't need to rewrite code if a new version of the library comes out. On the flip side, the library creator must have the freedom to make modifications and improvements with the certainty that the client code won't be affected by those changes.
This can be achieved through convention. For example, the library programmer must agree to not remove existing methods when modifying a class in the library, since that would break the client programmer's code. The reverse situation is thornier, however. In the case of a field, how can the library creator know which fields have been accessed by client programmers? This is also true with methods that are only part of the implementation of a class, and not meant to be used directly by the client programmer. But what if the library creator wants to rip out an old implementation and put in a new one? Changing any of those members might break a client programmer's code. Thus the library creator is in a strait jacket and can't change anything.
But I can't imagine a real situation where this can happen.
Can someone show me a practical example of this in real life?
This is how I imagine this:
public void print(String message)
{
System.out.println(message);
}
What difference does it make if a library client knows this implementation or not?
The implementation is not really hidden from view. Especially since most libraries out there that you will use are open source. "Hidden", in this case, refers to anything that is not part of the public API. The public API of a library consists of the public methods and fields that a library exposes. Once a library releases a version, it should continue to support the public API on future versions. Anything else is considered hidden and users of that library cannot rely on that "hidden code" being there in future version of that library.
EDIT:
But how could the client rely on code if it was not hidden, for example?
So lets say that a library comes out with a method that looks like this
public void doSomething(CharSequence x);
This is considered not hidden because it is public. Me as a user of that method is expecting it to exist in future versions of that library. So I am expecting that the input to that method is a CharSequence. If the author of that library wants to change that to String then that would be wrong. They should not change that CharSequence to a String because the users of the previous version are expecting CharSequence and switching it to a String might have negative consequences when the previous users of the library upgrade to the new version. In this case, the code might not compile.
So basically, if it is not hidden (aka part of the public API) then the author should not make any changes to the public API that would make previous versions of the library to not work.
This comes up all the time and there are ways around it. For example, when log4j upgraded to version 2, their changes were so dramatic that their API had to break and hence created a whole new library called log4j 2. So its a completely different library with different package names. It is not a new version of the old library, its a new library with similar name.
As a contrast to that, take a look at the Java SE's HashTable class. This is old class that should not be used anymore. But Java has a strict rule that the old public API of previous versions must still be supported in new versions. So Java cannot do what log4j did.
Another example is Spring. Spring tries to follow the approach that Java did, in that you only need to update the version and your old code should work. But Spring does deprecate parts of its public API. It will remove old classes and methods that are public but that it really does not want people to use anymore. In this case, me as a user of Spring might find it hard to upgrade from version 1 to version 4, for example. Mainly because some of the public API might have been deprecated.
So here I have given three different ways library writers have tackled this situation.
1) Side steps the old version and create a whole new library. E.g. Log4j.
2) Be strict and always support old public AIP's. E.g. Java.
3) Slowly deprecate old public API methods or classes. E.g. Spring.
Me as a user of these libraries would prefer that old public API be supported. I have used all three of those examples. I have had to work with old HashTable classes on legacy code I was upgrading to Java 8 and was happy that it was still supported. I have felt the pain of upgrading from log4j 1 to log4j 2. I have also upgraded Spring on a complicated project and have had adverse affects that needed to be troubleshooted. I can tell you that being strict to your old public API's is easiest on the users of said library.
There are many examples in the real world for this. For instance, if you consider buying a grocery previously v/s buying a grocery now. Or building a house previously v/s building a house now.
As time goes on the implementation changes of anything, but still the end result is same like bought grocery or built house. So, the library must have methods like buyGrocery() or buildHouse(), the implementation of which keeps on changing, but the user of the library still calls the same methods to attain the end results. Hope this answered your query.
Cheers!
Say for example, you're working with a LinkedList of names, and you make a utility method to print all the names in the list:
public void print(LinkedList<String> names)
{
for (String name : names)
System.out.println(name);
}
This works, but it limits you to only using a LinkedList. What if for some reason, some other code that you have runs slowly with a LinkedList, so you change it to an ArrayList? Well, now you have to go and change this method too.
public void print(ArrayList<String> names)
{
for (String name : names)
System.out.println(name);
}
But within this method, it doesn't matter if it is a LinkedList or an ArrayList, as long as you can iterate over it. This is where you want to hide the implementation details from your code, by using an interface:
public void print(Iterable<String> names)
{
for (String name : names)
System.out.println(name);
}
Now, you don't even have to pass in a List - you could pass in a HashSet, and it would still work. So, from your original qoute:
A primary consideration in object-oriented design is separating the things that change from the things that stay the same
The things that change, in this case, would be how you iterate over the collection, represented by the ArrayList and LinkedList implementations.
The thing that stays the same is the fact that you can iterate over the collection, which is what the Iterable interface represents.
A simple example could be if a log method was used for logging errors. Maybe first all it did was print to the console. Then later you wanted to write errors to a file:
public void log(String message)
{
// write to file
}
Then later you decided to write to a database or make a remote call:
public void log(String message)
{
// make network call
}
As long as the implementation is hidden, clients can continue calling log() and nothing will break because you did not change the method signature.
You can also have multiple implementations of this method by extracting an interface, as shown by #tima.
At the end of a controller request method, we usually do something like :
modelAndView.setViewName("welcomePage");
return modelAndView;
or
return "welcomePage";
Despite this way being simple and efficient, am I the only one to find these "magic strings" wrong ?
The same "welcomePage" string could be used several times in the same class or in other classes, thus breaking the "Don't repeat yourself" principle. Moreover, if I happened to rename "welcomePage.jsp", I would have to replace en masse all the occurences of "welcomePage" in the project.
The first solution that comes in mind would be to transform these (possibly shared) strings into (possibly centralized) constants or enumerations. But I am not sure this is the way to go with Spring MVC.
What do you think about these kind of "magic strings" ? Does Spring MVC allow to return views in a neater way ? If not, what solution would you recommend ?
1) I got over it when I realized my aversion to strings in code was based on things I learned by rote as an undergrad from people for whom EMACS was the pinnacle of all IDEs. Is AppConstants.ViewNames.WELCOME_PAGE really better than "welcomePage"? It is obvious in intent and easy to understand. Most of the time when I see people insist every string ever used more than once be a constant, the constant names are so close to the string names so that the code makes sense, that if you did change the, it wouldn't make any sense unless you change the constant name too anyway. /rantoff Changing it takes 15 seconds in a modern IDE.
2) The view resolver can automatically render /welcomePage.htm with WEB-INF/jsp/welcomePage.jsp (or whatever you set up). There is no reason to specify a view specifically by name unless you want to render a JSP whose name does not match the html doc requested in the URL path.
3) structure your pages so as to take advantage of #2 above and not need to specify explicit view names.
EDIT: There must be some way I can approach this without writing a whole new debugger. I'm currently looking into ways to build on top of the existing java debugger. If anyone has any ideas on how to grab information the Java debugger already has (about stack frames, variables, raw data etc.), that would be really helpful.
--
What I'm trying to do is I have this framework/API built on Java, and I would like to write an eclipse plugin debugger that is customized to my framework. Here is a simple example:
I have two classes, one called scope and one called variable. The scope holds a map of variables. The code is all in java, but I'm using this scope-variable relationship almost like a new language, and would like a variable debug tab that gives me a list of currently active scopes with the variables that are currently stored inside. Here is some code:
import java.util.Hashtable;
public class Scope {
private Hashtable<String, Variable> variableList = new Hashtable<String, Variable>();
// constructor
public Scope(){
}
public void put(String key, Variable v){
variableList.put(key, v);
}
public Variable get(String key){
return variableList.get(key);
}
}
public class Variable {
private String value;
private String name;
public Variable(String aName, String aValue){
name = aName;
value = aValue;
}
public String getValue(){
return value;
}
public String getName(){
return name;
}
public void setValue(String aValue){
value = aValue;
}
}
This is obviously an extremely simple example, but I would like to accomplish something similar to this where I can get a variables window, set a breakpoint, and have a "debugger" list out my active scope objects and the variable objects inside.
I've been trying to read and understand: http://www.eclipse.org/articles/Article-Debugger/how-to.html
and its pretty dense (as well as extremely outdated), but I will try to take some time to understand it. I just wanted to see if anyone had any high level recommendations on how to approach this type of problem, as I have little experience developing plugins in eclipse or making debuggers.
Thanks!
Not an easy task. That article is still the main reference, I think. Old, but not outdated. Try to digest it, and preferably to make it work. Before it, you should have a minimal experience developing Eclipse plugins.
There are many pieces in the picture, but the first thing you must understand is that when Eclipse is debugging something (assuming we are using the standard debug model), we have two separate "worlds": the Eclipse side, and the interpreter side (or, if you prefer, the "local" and "remote" sides).
Int the Eclipse side, the programming involves a cooperation between some Eclipse core classes and some classes of your own, which extend or implement some Eclipse classes/interfaces:
A "launchConfigurationType" (extension point in your plugin.xml) which causes the apparition of a new custom configuration when you click "Debug As -> New Configuration); this goes togetther with some "launchConfigurationTabGroups" definition that defines the "Tabs" dialogs that will appear in your custom launch configuration (eg) (each Tab will have its own class typically).
The launchConfigurationType is typically associated to a LaunchDelegate class, which is sort of your bootstrap class: it has the responsability of creating and starting a running/debugging instance, both on the Eclipse side and on the "interpreter" (or "remote") side.
On the Eclipse side, the running/debugging instance is represented by a IDebugTarget object and its children (the implementation is your responsability); this is created by the LaunchDelegate and "attached" to the remotely running process at launching time.
The remote side, the interpreter or program you are actually debugging, can be anything: a binary executable, a perl script, some app running in a some site (perhaps also a local Java program; but, even in this case, this would probably run in its own JVM, not in the debugging Eclipse JVM!). Your IDebugTarget object must know how to communicate to the "remote interpreter" (eg, by TCP) and perform the typical debugger tasks (place breakpoints, step, run, ask for variables, etc) - but the protocol here is up to you, it's entirely arbitrary.
What is not arbitrary is the hierarchy of your custom classes that the running Eclipse debugger will use: these should have a IDebugTarget as root, and should implement "The debug model" (see figure in article). As said above, the IDebugTarget object is who understands how to make the translation between the EClipse side and the remote side (see this image)
having worked on the eclipse edc debugger, it sounds like writing a whole debugger is not so much what you want.
it sounds like while running the debugger, you will have access to the objects that have the variables and scopes you are interested in.
you can use toString() in the classes themselves or use detail formatters to display a variation on the information you want. the toString() call can get quite detailed and nest into calls, show whole arrays, etc. detail formatters can also be quite complex.
see http://www.robertwloch.net/2012/01/eclipse-tips-tricks-detail-formatter/ . it's the best of several URLs (i have no association with the author).
once you are happy with the output of the Variable and Scope objects, you should be able to add watch expressions that will always show them in your expressions window (thus you don't have to rely on local variables in the stack frame you may be in).
this should then give you the list of Variables and Scopes from your framework that you are tracking … hopefully without having to write an entire eclipse debugger plugin to do so.
ok, i'm going to add a second answer here … i guess i'm not familiar enough with the state of your environment to know why custom detail formatters would not do the trick. for most cases, i think they'll provide you what you're looking for.
but if you're really interested in creating another view holding these items, then you could check out the eclipse jdt project . it's entirely possible that the extension points it provides will give you access to the internal variables and stack-frame information that you're looking to add, and also perhaps some UI that will make your job easier.
in other words, you might not have to write an entirely new debugger plugin, but perhaps a plug-in that can work together with jdt.
the site has pointers to the project plan, source repositories, the bugzilla issue tracking database (used for both bug-tracking and new feature discussion). perhaps some of those who are experts on jdt can help weigh in with their opinions about what will best suit your needs.
I would like to know which is in your opinion the best way to parse a Java file and automatically change either a variable name, a method name or the class name. I would like to do so because I want to offuscate some code by just changing one small part of it (one of the three cited above).
For example I could have a class that has a global variable public static final int index = 0 and I would like to change it to public static final int xxx = 0. Of course i should be replaced to xxx in each occurrence in the file. Same goes for class name or method name.
I've been told ANTLR may work for me, but I've never used it and I don't want to waste time learning it if then I discover it's not suited for my purpose.
Thanks
EDIT:
I do not need to obfuscate the code, I need to change a small part of it. Either one of those mentioned above.
If you only need to change a few such identifiers, then refactoring (supported by most IDEs, including Eclipse) is simple, quick, and reliable.
If you need to change a lot (for example, if you're trying to replace uses of english with roughly equivalent identifiers in a foreign language - e.g., counter => compteur), then I'd personally find myself using something scriptable, like sed or Perl. And I'd be very careful to make sure I was hitting exact matches (e.g., when changing lie to truth, that I don't also change belief' to 'betruthf)
One caution if you go with an automated, do-a-lot-at-a-time solution: be very sure you can test functionality before and after to assure that you haven't broken anything.
Maybe the easiest is to use an existing code obfuscator, like the free Proguard :
http://proguard.sourceforge.net/
Use a code obfuscator to do the work for you.
Or use an IDE like Eclipse, which has this kind of thing built in using the Refactor menu.
I started to work in translating a Java program which has tens of dialog classes to deal with. I wonder how is it possible to create a parameter that is understood in all of those classes, without having to declare it in each one.
Actualy are two parameters. Tried with something like:
public Locale currentLocale = new Locale("en");
public ResourceBundle text = ResourceBundle.getBundle("MessagesBundle", currentLocale);
in the launching class of the program but had no luck.
Any tip?
without having to declare it in each one.
There are two general approaches:
Singleton pattern.
Store the reference in the thread using ThreadLocal.
Either way, you need to take a lot of caveats into account. Singletons doesn't work well in environments with multiple classloaders/JVM's and ThreadLocals doesn't work well when you spawn multiple threads yourself to process the business task. You need to understand those caveats very well before continuing.
The safe approach would be to create the object only once during application's startup in some front controller class and pass it as argument into the business/model objects whenever needed.
Set a Parent ResourceBundle
Use the ResourceBundle.setParent() method. If a specific key cannot be found in the current ResourceBundle it will search the parent ResourceBundle.
getBundle will automatically search for parents
As the JavaDoc for ResourceBundle.getBundle(String, Locale, ClassLoader) states, this automatically happens when you load a resource bundle for a specific Locale and a bundle with the same base name can be found without the locale suffix.
In your example the ResourceBundle will be loaded from a file (.properties extension is optional) named:
MessagesBundle_en.properties
But it will also look for a generic
MessagesBundle.properties
and set this as the parent. If you provide this generic file as well, it will be used as a default whenever a key in a specific locale bundle cannot be found.