How do I access private fields with AspectJ? - java

I am investigating AspectJ and its many uses and have discovered mixins.
I can find many examples employing pure AspectJ .aj aspects however I need to use only #AspectJ annotations.
What I am trying to achieve is the following:-
I have a class that I cannot amend, it has a private class variable that I need to interrogate after a particular class method has completed execution. This class does not have getter or setter methods associated with this private class variable.
public final class CannotAmend {
private Uri privateUri;
public final void methodOne(){}
public final void methodTwo(){}
public final void methodThree(){
privateUri = "something";
}
}
I require an aspect/mixin that can capture #After methodThree() and allow me to see the value set in privateUri.
Is this possible to achieve?
With #AspectJ annotations?
Where can I discover documentation/tutorial/examples of how to achieve this?

Within an aspect you can access the private field using the reflection API.
In the aspect you need two things:
A pointcut to define methods on which the aspect matches.
And a method annotated with #After containing logic that's executed after a method matched by the pointcut returns.
#Aspect
public class MyAspect {
#Pointcut("execution(* CannotAmend.methodThree(..))")
public void methodThreePointcut(){
}
#After("methodThreePointcut()")
public void afterMethod(JoinPoint joinPoint) throws NoSuchFieldException, IllegalAccessException {
Object instance = joinPoint.getThis();
Field privateUriField = instance.getClass().getDeclaredField("privateUri");
privateUriField.setAccessible(true);
String privateUri = (String) privateUriField.get(instance);
System.out.println(privateUri); // prints "something"
}
}
On a side note, using String constants to access a private field is not a clean solution. If sometime in the future the name of the variable changes or if it's removed, the aspect will break.

Not with mixins, but you can use #Around advice to get JoinPoint and get field through reflection.
For example:
#Around("execution(* *.methodThree())")
public Object getValue(ProceedingJoinPoint pjp) throws Throwable {
try {
return pjp.proceed();
} finally {
System.out.println(pjp.getThis().getClass().getDeclaredField("privateUri").get(pjp.getThis()));
}
}

Related

Create #Bean for mi method static [duplicate]

With this class
#Component
public class Sample {
#Value("${my.name}")
public static String name;
}
If I try Sample.name, it is always 'null'. So I tried this.
public class Sample {
public static String name;
#PostConstruct
public void init(){
name = privateName;
}
#Value("${my.name}")
private String privateName;
public String getPrivateName() {
return privateName;
}
public void setPrivateName(String privateName) {
this.privateName = privateName;
}
}
This code works. Sample.name is set properly. Is this good way or not? If not, is there something more good way? And how to do it?
First of all, public static non-final fields are evil. Spring does not allow injecting to such fields for a reason.
Your workaround is valid, you don't even need getter/setter, private field is enough. On the other hand try this:
#Value("${my.name}")
public void setPrivateName(String privateName) {
Sample.name = privateName;
}
(works with #Autowired/#Resource). But to give you some constructive advice: Create a second class with private field and getter instead of public static field.
Soruce of this info is this: https://www.baeldung.com/spring-inject-static-field
Spring uses dependency injection to populate the specific value when it finds the #Value annotation. However, instead of handing the value to the instance variable, it's handed to the implicit setter instead. This setter then handles the population of our NAME_STATIC value.
#RestController
//or if you want to declare some specific use of the properties file then use
//#Configuration
//#PropertySource({"classpath:application-${youeEnvironment}.properties"})
public class PropertyController {
#Value("${name}")//not necessary
private String name;//not necessary
private static String NAME_STATIC;
#Value("${name}")
public void setNameStatic(String name){
PropertyController.NAME_STATIC = name;
}
}
This is my sample code for load static variable
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class OnelinkConfig {
public static int MODULE_CODE;
public static int DEFAULT_PAGE;
public static int DEFAULT_SIZE;
#Autowired
public void loadOnelinkConfig(#Value("${onelink.config.exception.module.code}") int code,
#Value("${onelink.config.default.page}") int page, #Value("${onelink.config.default.size}") int size) {
MODULE_CODE = code;
DEFAULT_PAGE = page;
DEFAULT_SIZE = size;
}
}
For those who want to use ApplicationContext in the main class of a Spring Boot application, you can just use the return value of SpringApplication.run.
Although workarounds may need to be implemented, one should try to avoid them in most scenarios if possible. Spring is great at handling dependency injection and treats most objects as Singletons. This means that Spring can handle the creation of objects for you, and the injection of these objects at runtime. When combining this with the fact that your Spring managed bean is likely a Singleton, the use of static methods and variables is largely unnecessary. You can simply autowire in an instance of the object you are looking for at the constructor level or variable level and reference the non-static version of the method or variable. This is ideal and behaves similarly to a static reference. Non static variables are basically static because you are only ever using one instance of the object in every part of the code and because of dependency injection you are never handling the instantiation of the object, just like with a static reference! Great! Now I'm sure there are instances where you need the work around (i.e. you aren't using dependency injection or class is not a singleton), but try to not use workarounds if possible. Also this is just my 2 cents. Someone may be able to offer 3. (:
public class InjectableClass{
#Value("${my.value}")
private String myString;
public String nonStaticMethod(){
return myString;
}
}
public class LogicClass{
private InjectableClass injectableClass;
#Autowire
public LogicClass(InjectableClass injectableClass){
this.injectableClass = injectableClass;
}
public void logicClassMethod(){
System.out.println("Hey! Here is the value I set on myString: " +
injectableClass.nonStaticMethod() + ". That was
basically like using a static method!");
}
}

Guice assisted inject overuse alternatives, dependency injection vs non-DI constructors

The main reasons I like passing in runtime dependencys in constructors are:
It makes the dependency required
It provides a central place to set instance variables
Setting the dependency as an instance variable prevents you from
having to pass it around from method to method within the class or pass it in twice or more
to two or more public methods
This has led me to use a lot of Assisted Injects when using Guice. This creates extra code compared to not using DI so reading things like this:
How exactly is Assisted-inject suppose to be use to be useful?
It seems like most people don't pass the runtime(derived, not available at startup) dependencies in constructors using assisted inject, and instead pass them in individual methods. Thats fine for the simple class given in the above stackoverflow post where there is only one method that relies on the dependency:
public class SomeClass {
#Inject
SomeClass(...) {
...
}
public void doWork(int s) { /* use s */ ... }
}
But what if the class has many methods that use the dependency? Do you pass it from the public method to private methods and require it passed in on all public methods?
For example:
public class SomeClass {
#Inject
SomeClass(...) {
...
}
public void doWork(int s) {
/*some code */
someOtherMethod(s);
anotherMethod(s);
}
//any private method that needs it gets it passed in as a param
private void someOtherMethod(int s)...
private void anotherMethod(int s)...
//require it passed in all public methods that need it
public void anotherPublic(int s){
someOtherMethod(s);
}
}
As opposed to using constructors this adds a bit of extra code as seen here:
public class SomeClass {
private int s;
SomeClass(int s) {
this.s = s;
}
public void doWork() {
someOtherMethod();
anotherMethod();
}
private void someOtherMethod()...
private void anotherMethod()...
public void anotherPublic(){}
}
Or would you set the instance var from the service method like this?
public class SomeClass {
Integer s;
#Inject
SomeClass(...) {
...
}
public void doWork(Integer s) {
/***set instance var this time***/
this.s = s;
someOtherMethod();
anotherMethod();
}
private void someOtherMethod()...
private void anotherMethod()...
public void anotherPublicMethod(){
if(s==null){ //check if s was set already
throw new IllegalStateException();
}else{
/* do something else */
}
}
}
Or would you pass the dependency into the other public method as a param and set the instance var there as well? For Example:
public class SomeClass {
#Inject
SomeClass(...) {
...
}
public void doWork(Integer s) {
/***set instance var this time***/
this.s = s;
someOtherMethod();
anotherMethod();
}
private void someOtherMethod()...
private void anotherMethod()...
public void anotherPublicMethod(Integer s){
this.s = s;
/* do something else */
}
}
So I think passing the param from method to method or throwing illegal state exceptions to check for it isn't ideal compared to using normal constructors, but obviously there are advantages/disadvantages to any framework/pattern.
If I am just not separating my objects in the ideal way, please let me know some guidelines you use, ie "I only use one public method per service class, see this book or post about it:.." .
What do you guys do in the above situations?
You nailed down some great reasons to use assisted injection in your question: It ensures that the object instances only ever exist in a fully-initialized state, keeps your dependencies together, and frees the object's public interface from requiring a predictable parameter in every method.
I don't really have any alternatives to add, other than the ones you mentioned:
Adding a setter method for that dependency, probably requiring IllegalStateException checks or a good default value
Creating an initialize(int s) pseudoconstructor method with the same IllegalStateException checks
Taking in the parameter in individual methods
Replacing the FactoryModuleBuilder boilerplate with a custom factory, thereby creating more extra boilerplate you're trying to avoid
My favorites are the two you seem to be deciding between--assisted injection or taking the parameter in every method--mostly because they both keep the object in a predictable, usable state at all times. My decision between them rests on what kind of state the object should carry, whether that state is mutable, and how I want to control instances. For Car.licensePlateNumber, the license plate number may vary with the car instance; each car has one license plate number that (in this example) never varies, and the car isn't valid without it, so it should be a constructor argument. Conversely, Repository<T> may frequently take in the same T instance in all of its methods, but a Repository is still a Repository no matter which instance you pass in, and you may want the freedom to reuse that instance without creating a new one for each T (as you may have to do with assisted injection). Both designs are valid, and each one is optimal for a certain set of cases.
Remember that there shouldn't really be that much extra code required for assisted injection:
/** In module: install(new FactoryModuleBuilder().build(SomeClass.Factory.class)); */
public class SomeClass {
public interface Factory {
SomeClass create(int s);
}
private final int s;
#Inject
SomeClass(/* ..., */ #Assisted int s) {
this.s = s;
}
public void doWork() { /* ... */ }
}

#value with static field in spring [duplicate]

With this class
#Component
public class Sample {
#Value("${my.name}")
public static String name;
}
If I try Sample.name, it is always 'null'. So I tried this.
public class Sample {
public static String name;
#PostConstruct
public void init(){
name = privateName;
}
#Value("${my.name}")
private String privateName;
public String getPrivateName() {
return privateName;
}
public void setPrivateName(String privateName) {
this.privateName = privateName;
}
}
This code works. Sample.name is set properly. Is this good way or not? If not, is there something more good way? And how to do it?
First of all, public static non-final fields are evil. Spring does not allow injecting to such fields for a reason.
Your workaround is valid, you don't even need getter/setter, private field is enough. On the other hand try this:
#Value("${my.name}")
public void setPrivateName(String privateName) {
Sample.name = privateName;
}
(works with #Autowired/#Resource). But to give you some constructive advice: Create a second class with private field and getter instead of public static field.
Soruce of this info is this: https://www.baeldung.com/spring-inject-static-field
Spring uses dependency injection to populate the specific value when it finds the #Value annotation. However, instead of handing the value to the instance variable, it's handed to the implicit setter instead. This setter then handles the population of our NAME_STATIC value.
#RestController
//or if you want to declare some specific use of the properties file then use
//#Configuration
//#PropertySource({"classpath:application-${youeEnvironment}.properties"})
public class PropertyController {
#Value("${name}")//not necessary
private String name;//not necessary
private static String NAME_STATIC;
#Value("${name}")
public void setNameStatic(String name){
PropertyController.NAME_STATIC = name;
}
}
This is my sample code for load static variable
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class OnelinkConfig {
public static int MODULE_CODE;
public static int DEFAULT_PAGE;
public static int DEFAULT_SIZE;
#Autowired
public void loadOnelinkConfig(#Value("${onelink.config.exception.module.code}") int code,
#Value("${onelink.config.default.page}") int page, #Value("${onelink.config.default.size}") int size) {
MODULE_CODE = code;
DEFAULT_PAGE = page;
DEFAULT_SIZE = size;
}
}
For those who want to use ApplicationContext in the main class of a Spring Boot application, you can just use the return value of SpringApplication.run.
Although workarounds may need to be implemented, one should try to avoid them in most scenarios if possible. Spring is great at handling dependency injection and treats most objects as Singletons. This means that Spring can handle the creation of objects for you, and the injection of these objects at runtime. When combining this with the fact that your Spring managed bean is likely a Singleton, the use of static methods and variables is largely unnecessary. You can simply autowire in an instance of the object you are looking for at the constructor level or variable level and reference the non-static version of the method or variable. This is ideal and behaves similarly to a static reference. Non static variables are basically static because you are only ever using one instance of the object in every part of the code and because of dependency injection you are never handling the instantiation of the object, just like with a static reference! Great! Now I'm sure there are instances where you need the work around (i.e. you aren't using dependency injection or class is not a singleton), but try to not use workarounds if possible. Also this is just my 2 cents. Someone may be able to offer 3. (:
public class InjectableClass{
#Value("${my.value}")
private String myString;
public String nonStaticMethod(){
return myString;
}
}
public class LogicClass{
private InjectableClass injectableClass;
#Autowire
public LogicClass(InjectableClass injectableClass){
this.injectableClass = injectableClass;
}
public void logicClassMethod(){
System.out.println("Hey! Here is the value I set on myString: " +
injectableClass.nonStaticMethod() + ". That was
basically like using a static method!");
}
}

How to control global variable in unitTest

Is it possible to control the value of the global variable in the class that I test?
The global variable is used in a private method, so I use a public method (in the same class) to pass through it.
How can I say that mListValService != null?
public class Myclass {
//my global variable
private ListValServiceRemote listValService = null;
public String getCodeValeurRef(Long idValeur) {
return getListValService().getRlvCode(idValeur);
// I want 100% coverage on this method so i have to change the value
// of mListValService.
private ListValServiceRemote getListValService() {
if (listValService == null) {
listValService = ServiceGetter.getListValService();
}
return listValService;
}
ReflectionTestUtils from spring-test might be a solution to access the field value. You can also use plain old reflection, add getter/setter to the field or make the field protected and put the test in the same package as the tested class.
Sample test:
public class MyclassTest {
private MyClass myClass;
#Before
public void setup() {
this.myClass = new MyClass();
}
#Test
public void testGetListValServiceWhenFieldIsNull() {
assertNotNull(this.myClass.getListValService());
}
#Test
public void testGetListValServiceWhenFieldIsNotNull() {
final ListValServiceRemote lvsr = new ListValServiceRemote();
ReflectionTestUtils.setField(this.myClass, "listValService", lvsr);
assertSame(lvsr, this.myClass.getListValService());
}
}
First of all, seems you are not using IoC technique, and hence you have problems while unit testing the code.
Secondly, a private is the private, don't test it. Your code should be tested and covered only by using public methods. If some code is not reachable via public interface, then it is not reachable at all. Why do you want to test it then?
This particular code could be easily 100% covered if you just invoke getCodeValeurRef() twice. And also if you would have listValService == null, it will cause NullPointerException failing the test anyway, so an assert is not required.
You could expose the getListValService() method as package-private, then call it in a test. You can confirm the same value is returned each time:
#Test
public void sameListValTest() {
Myclass foo = // construct this somewhow
assertTrue(foo.getListValService() == foo.getListValService());
}
This will give you 100% coverage without fiddling with a private field.
Or you could just call getCodeValeurRef() twice in your test to achieve the same results. Anything that causes the getListValService() to execute twice will give you 100% coverage. Exposing it as package-private allows you to verify that you are re-using the same field, not creating one each time (if that's important).

Match argument with custom annotation on class - detect in runtime

I have annotation like #SecureObject, which might be applied to some classes. Additionally there is the ORM, which provides method like
public ObjectID get(Class paramClass, Object object);
Now I need to create aspect, which will be triggered only in case if paramClass is annotated with #SecureObject.
Straightforward solution like:
#Before("call(public * some.orm.Datastore.get(..,#SecureObject *,..))"
void runBefore() {
// method code
}
does not work - method is never invoked. but wired (checked with aspectj -debug).
Is it possible to achieve such behavior with AspectJ, and if so - how?
The problem is that the first parameter of your get() method is of type Class.
Given that, you can't use an annotation-based method signature pattern. One possible solution is to use an if() pointcut expressions:
package aspects;
#Aspect
public class MyAspect {
#Pointcut("if() && call(public * some.orm.Datastore.get(..)) && args(paramClass,..)")
public static boolean runBefore(JoinPoint jp, Class paramClass) {
return paramClass.isAnnotationPresent(annotation.SecureObject.class);
}
#Before("runBefore(jp, paramClass)")
public void runBeforeAdvice(JoinPoint jp, Class paramClass) {
System.out.println("annotated!");
}
}
Note: This pointcut also triggers if no #SecureObject annotation is present but the if() condition gets evaluated at runtime.

Categories