Java: Internationalization / ResourceManager in interface files - java

I have an annotation in my java project which has some default strings in it:
public #interface MyInterface {
String message() default "Dependency for field; must be set here";
// ...
}
How can I do internationalization here? In my classes I would load the string via a ResourceManager
public class ValidationDocument {
private String message = ResourceManager.findLiteral("ValidationDocument", "default.message");
// ...
}
I can't load the ResourceManager in the annotation definition. What would be a good way to do the internationalization here?

You're right, you cannot do it, because annotations are evaluated at compile time and thus you can only use constants, or expressions that only involve constants. Information that can only by available at run-time, such as one retrieved by calling methods, even static ones, therefore cannot be assigned in annotations.
Annotations are not designed to be dynamically modified at run-time, so you will need to change your approach.
I could only suggest to do something like:
public #interface MyInterface {
String messageKey() default "myinterface.mykey";
// ...
}
Then, your code that actually references the #MyInterface annotation instance, would use the messageKey to look-up the message in the ResourceManager. Might work depending on what you're trying to achieve with it.

Related

Alternative To Singleton Util Class

So I have a class like so:
public class HBaseUtil {
private final String fileName = "hbase.properties";
private Configuration config;
private HBaseUtil() {
try {
config = new PropertiesConfiguration(fileName);
} catch (ConfigurationException e) {
// some exception handling logging
}
}
// now some getters pulling data out of the config object
public static String getProperty(String fieldKeyName) {...}
public static String getColumnFamily(String fieldName) {...}
// ... some more getters
// NO setters (thus making this a read-only class)
}
Thus, basically I have for myself a Singleton class, that the very first time that it is put to use, sets up a configuration object, and then simply keeps listening for get calls. There are a number of problems with this class:
Unit testing the static methods within class HBaseUtil becomes difficult because of a tight-knit coupling between the Singleton and the configurations file.
What I really want is me being able to supply the filename/filename+path to the class so that it can go in there, read the configuration properties from that file and offer them to incoming read requests. One important note here though: I need this flexibility in specifying the properties file ONLY ONCE per JVM launch. So I certainly don't need to maintain state.
Here is what I was able to come up with:
Instead of a Singleton, I have a normal class with all static methods and no explicit constructor defined.
public class HBaseUtil {
// directly start with getters
public static String getProperty(Configuration config, String fieldKeyName) {...}
public static String getColumnFamily(Configuration config, String fieldKeyName) {...}
// ...and so on
}
And then, instead of using the class in my other code like such:
HBaseUtil.getProperty(String fieldKeyName)
I'd use it like so:
Configuration externalConfig = new PropertiesConfiguration("my-custom-hbase.properties");
HbaseUtil.getProperty(externalConfig, fieldKeyName)
My questions:
Am I even thinking in the right direction? My requirement is to have the flexibility in the class only ONCE per JVM. All that needs to be configurable in my project for this, is the location/contents of the HBase .properties file. I was thinking having a Singleton is overkill for this requirement.
What other better approaches are there for my requirement (stated in above point)?
Thanks!
Note: I've read this StackOverflow discussion, but now it's gotten me even more confused.
You should avoid all static methods and instead design a class which does not mandate its lifecycle: it can be a typical immutable POJO with a public constructor.
Then, when you need it as a singleton, use it as a singleton. For testing, use it in some other way.
Usually, dependency injection is the preferred avenue to solve these problems: instead of hard-coding a pulling mechanism for your configuration object, you have the object delivered to any class which needs it. Then you can decide late what bean you will deliver.
Since you are probably not using Spring (otherwise dependency injection would be your default), consider using Guice, which is a very lightweight and non-intrusive approach to dependency injection.

Java type level annotation and private member visibility

I'm trying to externalize the baseurl of a spring #Controller into a static String member of the controller class. If i do so i have to declare the member public - otherwise it will not be visible to the #RequestMapping annotation. I can't understand why - isn't the annotation part of the class?
Can someone explain why i am forced not to use private here?
Invalid:
#Controller
#RequestMapping(PendingApprovalsController.CONTROLLER_URL)
public class PendingApprovalsController {
private static final String CONTROLLER_URL = "/some/url";
...
}
Valid:
#Controller
#RequestMapping(PendingApprovalsController.CONTROLLER_URL)
public class PendingApprovalsController {
public static final String CONTROLLER_URL = "/some/url";
...
}
An annotation is an ordinary Java class itself. It can't see the members of an annotated class unless they are visible to it, using normal Java rules. Furthermore the existence of annotations may be used by other code at runtime to operate on the members of the annotated class; if those members are not visible, those operations can't be performed.
This page from the JDK documentation package talks about how to define custom annotations, and how to consume annotations applied in code, and it's enlightening in this regard. To define an annotation type, you do something like
public #interface Copyright {
String value();
}
Your custom annotation is defined as a special kind of Java interface; in user, the JVM supplies a runtime implementation as needed. But the key thing to note is how you use your custom annotation, for example:
Method m = ... // Get a java.lang.reflect.Method object from somewhere
if (m.hasAnnotation(Copyright.class)) ...
Note that here we refer to the class object of the annotation type, demonstrating that an annotation is compiled to a normal Java type.

Using static variables in Spring annotations

I'm using spring's PreAuthorize annotation as follows:
#PreAuthorize("hasRole('role')");
However, I already have 'role' defined as a static String on another class. If I try to use this value:
#PreAuthorize("hasRole(OtherClass.ROLE)");
I get an error:
org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 14): Field or property 'OtherClass' cannot be found on object of type 'org.springframework.security.access.expression.method.MethodSecurityExpressionRoot'
Is there a way to access static variables like this with a PreAuthorize annotation?
Try the following which uses Spring Expression Language to evaluate the type:
#PreAuthorize("hasRole(T(fully.qualified.OtherClass).ROLE)");
Be sure to specify the fully qualified class name.
Documentation
You can also create a bean container with roles, like:
#Component("R")
public final class RoleContainer {
public static final String ROLE_A = "ROLE_A";
}
then on controller you can use:
#PreAuthorize("hasRole(#R.ROLE_A)")
To make it possible to write expressions without package names:
<sec:global-method-security>
<sec:expression-handler ref="methodSecurityExpressionHandler"/>
</sec:global-method-security>
<bean id="methodSecurityExpressionHandler" class="my.example.DefaultMethodSecurityExpressionHandler"/>
Then extend the DefaultMethodSecurityExpressionHandler:
public class DefaultMethodSecurityExpressionHandler extends org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler {
#Override
public StandardEvaluationContext createEvaluationContextInternal(final Authentication auth, final MethodInvocation mi) {
StandardEvaluationContext standardEvaluationContext = super.createEvaluationContextInternal(auth, mi);
((StandardTypeLocator) standardEvaluationContext.getTypeLocator()).registerImport("my.example");
return standardEvaluationContext;
}
}
Now create my.example.Roles.java :
public class Roles {
public static final String ROLE_UNAUTHENTICATED = "ROLE_UNAUTHENTICATED";
public static final String ROLE_AUTHENTICATED = "ROLE_AUTHENTICATED";
}
And refer to it without package name in annotations:
#PreAuthorize("hasRole(T(Roles).ROLE_AUTHENTICATED)")
instead of:
#PreAuthorize("hasRole(T(my.example.Roles).ROLE_AUTHENTICATED)")
Makes it more readable imho. Also roles are now typed. Write:
#PreAuthorize("hasRole(T(Roles).ROLE_AUTHENTICATEDDDD)")
and you will get startup errors that wouldn't have been there if you wrote:
#PreAuthorize("hasRole('ROLE_AUTHENTICATEDDDD')")
Try something like this:
#PreAuthorize("hasRole(T(com.company.enumpackage.OtherClass).ROLE.name())");
If your OtherClass enum is declared as public static, then you need to use $ sign:
#PreAuthorize("hasRole(T(com.company.ParentTopLevelClass$OtherClass).ROLE.name())");
name() to prevent futer problems if toString() will be overriden later
The accepted answer from Kevin Bowersox works, but I didn't like having the T(fully.qualified.path) stuff so I kept looking. I started by creating a custom security method using the answer from James Watkins here:
How to create custom methods for use in spring security expression language annotations
However, instead of a String, I used my enums.Permissions class as the parameter type:
#Component
public class MySecurityService {
public boolean hasPermission(enums.Permissions permission) {
...do some work here...
return true;
}
}
Now the neat part is that when I call the hasPermission from an annotation, I don't have to have to type the whole path, but I do have to enclose it in single quotes:
#PreAuthorize("#mySecurityService.hasPermission('SOME_ROLE_NAME')")
Because the hasPermission method expects an Enum, it will automatically find the Enum value with that name. If it doesn't find it you'll get an exception:
org.springframework.expression.spel.SpelEvaluationException: Type conversion problem, cannot convert from java.lang.String to enums.Permissions
You can rename hasPermission to hasRole, in which case the only trade off is that you are trading T(fully.qualified.path) for #mySecurityService and extra single quotes.
Not sure if it is any better, but there it is. Since none of this is going to verify the values at compile time anyways, my next step is to make an annotation processor.
I also have to give credit to krosenvold for pointing out that spring can automatically convert to an enum:
https://stackoverflow.com/a/516899/618881

How do I use Local Variable Annotations for Wicket Authorization?

I'm rolling my own IAuthorizationStrategy for Wicket 1.5.x I've setup type annotation for pages to use with isInstantiationAuthorized(). It works well and I'd like to use annotations for isActionAuthorized() as well. Ideally I'd like to be able annotate local variables and then check the annotations in my AuthStrategy. From what I've read Local variable Annotation doesn't work that way.
Is there any kind of known work around, maybe some sort of Compile time annotation processing to turn an annotated local variable into an "anonymous" subclass with the annotation as a type annotation?
For the record, the annotation I'm trying to use looks like this:
#Retention(RetentionPolicy.Runtime)
#Target(ElementType.Type, ElementType.LOCAL_VARIABLE)
public #interface AdminOnly
{
int isVisible() default 0;
int isEnabled() default 1;
}
UPDATE
So based on #Xavi López'es answer what I was hoping to do isn't exactly possible.
Annotated LocalVariables should be available at compile time though. Is there some way maybe I could use them as a shortcut for boiler-plating the meta-data code examples that are available in Wicket Examples or the excellent Apache Wicket Cookbook?
I've struggled with a similar issue some time ago with Wicket 1.3.x, and didn't find any way to achieve this with annotations. Annotations on local variables can't be retained at run-time, as explained in the JLS (9.6.3.2. #Retention):
An annotation on a local variable declaration is never retained in the binary representation.
In this related question: How can I create an annotation processor that processes a Local Variable? they talked about LAPT-javac, a patched javac version to allow this. On their site there's a link to the Type Annotations Specification (JSR 308), which will hopefully address this subject (JDK 8 ?).
I ended up defining a plain old interface with a related functionality code:
public interface RestrictedComponent {
Integer getFunction();
}
The main problem with this approach is that it's not possible to make instant anonymous subclasses of a specific class implement other interfaces (such as Component c = new TextField() implements AdminOnly { }) , but you can always define Component extensions that just implement RestrictedComponent in a class:
public abstract class RestrictedTextField extends TextField implements RestrictedComponent { }
Finally, I ended up implementing a RestrictedContainer that just subclassed WebMarkupContainer and put every secured component inside one, modelling it with a <wicket:container> in the markup.
public class RestrictedContainer extends WebMarkupContainer implements RestrictedComponent {
private final Integer function;
public RestrictedContainer(String id, IModel model, final Integer function) {
super(id, model);
this.function = function;
}
public RestrictedContainer(String id, final Integer funcionalitat) {
super(id);
this.function = function;
}
public Integer getFunction() {
return function;
}
}
And then in the Authorization Strategy checked for component instanceof RestrictedComponent and returned true or false depending on user permissions on the associated function.

Java Annotations values provided in dynamic manner

I want to provide annotations with some values generated by some methods.
I tried this so far:
public #interface MyInterface {
String aString();
}
#MyInterface(aString = MyClass.GENERIC_GENERATED_NAME)
public class MyClass {
static final String GENERIC_GENERATED_NAME = MyClass.generateName(MyClass.class);
public static final String generateName(final Class<?> c) {
return c.getClass().getName();
}
}
Thought GENERIC_GENERATED_NAME is static final, it complains that
The value for annotation attribute MyInterface.aString must be a constant expression
So how to achieve this ?
There is no way to dynamically generate a string used in an annotation. The compiler evaluates annotation metadata for RetentionPolicy.RUNTIME annotations at compile time, but GENERIC_GENERATED_NAME isn't known until runtime. And you can't use generated values for annotations that are RetentionPolicy.SOURCE because they are discarded after compile time, so those generated values would never be known.
The solution is to use an annotated method instead. Call that method (with reflection) to get the dynamic value.
From the user's perspective we'd have:
#MyInterface
public class MyClass {
#MyName
public String generateName() {
return MyClass.class.getName();
}
}
The annotation itself would be defined as
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface #MyName {
}
Implementing the lookup for both of these annotations is rather straight-forward.
// as looked up by #MyInterface
Class<?> clazz;
Method[] methods = clazz.getDeclaredMethods();
if (methods.length != 1) {
// error
}
Method method = methods[0];
if (!method.isAnnotationPresent(MyName.class)) {
// error as well
}
// This works if the class has a public empty constructor
// (otherwise, get constructor & use setAccessible(true))
Object instance = clazz.newInstance();
// the dynamic value is here:
String name = (String) method.invoke(instance);
There is no way to modify the properties of an annotation dynamically like others said. Still if you want to achieve that, there are two ways to do this.
Assign an expression to the property in the annotation and process that expression whenever you retrieve the annotation. In your case your annotation can be
#MyInterface(aString = "objectA.doSomething(args1, args2)")
When you read that, you can process the string and make the method invocation and retrieve the value. Spring does that by SPEL (Spring expression language). This is resource intensive and the cpu cycles are wasted every time we want to process the expression. If you are using spring, you can hook in a beanPostProcessor and process the expression once and store the result somewhere. (Either a global properties object or in a map which can be retrieved anywhere).
This is a hacky way of doing what we want. Java stores a private variable which maintains a map of annotations on the class/field/method. You can use reflection and get hold of that map. So while processing the annotation for the first time, we resolve the expression and find the actual value. Then we create an annotation object of the required type. We can put the newly created annotation with the actual value (which is constant) on the property of the annotation and override the actual annotation in the retrieved map.
The way jdk stores the annotation map is java version dependent and is not reliable since it is not exposed for use (it is private).
You can find a reference implementation here.
https://rationaleemotions.wordpress.com/2016/05/27/changing-annotation-values-at-runtime/
P.S: I haven't tried and tested the second method.

Categories