Pointcut expression 'if()' contains unsupported pointcut primitive 'if' - aspectj

I am using AspectJ in my Spring boot project for AOP.
I have declared a if() point cut:
public class myPointCuts {
// a global boolean variable, value can be updated at runtime.
public static boolean IS_RESULT_FINE;
#Pointcut("if()")
public static boolean isResultFine() {
return IS_RESULT_FINE;
}
}
At compile time, I get error:
Initialization of bean failed;
nested exception is org.aspectj.weaver.tools.UnsupportedPointcutPrimitiveException: Pointcut expression 'if()' contains unsupported pointcut primitive 'if'
My declared dependencies:
implementation 'org.springframework:spring-aop:5.0.1.RELEASE'
implementation 'org.aspectj:aspectjweaver:1.9.4'
What is wrong with my if() point cut expression ?

Probably you are trying to use if() in Spring AOP, but as the error message "unsupported pointcut primitive 'if'" implies, if() is not available in Spring AOP, only in AspectJ, which is also explained in the corresponding Spring manual section. You find a positive and negative list there.
If you want to use if() you do need to switch to AspectJ with load-time weaving. But I am not sure it is worth switching the AOP framework for the sake of the if() pointcut which is not much more than syntactic sugar for an if (IS_RESULT_FINE) statement you could also just put right into your advice method.

Related

How to exclude classes from triggering Aspect method call

I have a method in an #Aspect service method called logChangesAndAnnounceNewContributions that fires whenever somewhere in the webapp the save method of Spring-data's JpaRepository is called. I don't want the logChanges method to be called when the save method is used within the Aspect class itself, so i used this in the pointcut definition !within(Services.SystemListenerService). But its not having any effect! The save method is still being called despite using this condition in the definition. The full definition looks like this:
#AfterReturning("execution(* org.springframework.data.jpa.repository.JpaRepository.save(..))" +
"&& !within(Services.SystemListenerService) && args(entity)")
private void logChangesAndAnnounceNewContributions(Object entity){
What am i missing here?
EDIT: I tried changing !within content to !within(#org.aspectj.lang.annotation.Aspect *) but that doesn't work either..
Assuming that Services.SystemListenerService is the fully qualified name of your aspect (class name SystemListenerService, package name Services with strange upper-case first letter), within() does not work because at the time of execution(* org.springframework.data.jpa.repository.JpaRepository.save(..)) we are not within(Services.SystemListenerService) anyway but rather within(org.springframework.data.jpa.repository.JpaRepository). So there is the logical error in your pointcut.
There are ways to solve this in AspectJ, such as
call(A) && !adviceexecution(),
execution(A) && !cflow(execution(B)),
but both pointcut types are unsupported in Spring AOP. So you
either need to activate full AspectJ via LTW in Spring
or abuse some Spring methods in order to get the real object underneath the proxy via ((Advised) myProxy).getTargetSource().getTarget() and call the method directly on that object from your aspect
or obtain a stack trace from a newly created exception or from the current thread and inspect it manually - very ugly.
Sorry, but Spring AOP is just "AOP lite", I think you should go for AspectJ. The second option is also a bit hacky but will probably work.

eclipselink static weaving with final fields on Java 9

I have some JPA annotated fields declared final like this:
#Column(name = "SOME_FIELD", updatable = false, nullable = false)
private final String someField;
Those fields are stored in the database when the entity is inserted in the database. They cannot further be updated. For the Java programming language, such fields can be considered final.
With the EclipseLink static weaving plugin, it's possible to lazy load entities, owing to some byte code instrumentation.
I don't know if such constructs (final fields) are officially allowed in JPA, but I like to use them, since they enforce at compile time that these fields are not meant to be updated.
In Java 8, programs built with such constructs run fine. But in Java 9, when the EclipseLink static weaving is involved, I get the following runtime exception:
Caused by: java.lang.IllegalAccessError: Update to non-static final field xxx.yyy.SomeEntity.someField attempted from a different method (_persistence_set) than the initializer method <init>
Such an error seems to be due to the following JVM specification:
Otherwise, if the field is final, it must be declared in the current
class, and the instruction must occur in an instance initialization
method () of the current class. Otherwise, an IllegalAccessError
is thrown.
Therefore, I feel like some weaving tools need some update to fulfill this JVM specification. The EclipseLink static weaving tool seems to be one of them.
Questions:
Are final field constructs such as those presented here allowed in JPA?
Is there a JDK 9 option to disable the check for final field assignment elsewhere than only in the instance initialization method() of the class (as a temporary workaround)?
Edit:
Final fields are not allowed in JPA, as per JPA specifications:
The entity class must not be final. No methods or persistent instance variables of the entity class may be final.
Are final field constructs such as those presented here allowed in JPA?
As mentioned in the release note JDK-8157181 as well there is a change brought to restrict Compilers to accept modification of final fields outside initializer methods.
According to the Java VM Specification, the putstatic bytecode is allowed to modify a final field only
if the field is declared in the current class (the class that declares the current method) and
if the putstatic instruction appears in the class or interfaceinitializer method <clinit> of the current class.
Otherwise, an IllegalAccessError must be thrown.
Similarly, the putfield bytecode is allowed to modify a final field only
if the field is declared in the current class and
if the instruction appears in an instance initializer method of the current class.
Otherwise, an IllegalAccesError must be thrown.
Methods that do not satisfy condition (2) violate the assumptions of the compilers. and have been kept under a check to implement the desired condition with Java 9.
You can follow the BugReport over the same for a detailed explanation.
Is there a JDK 9 option to disable the check for final field assignment elsewhere than only in the instance initialization method() of the class (as a temporary workaround)?
With the JDK 9 release, the HotSpot VM fully enforces the previously
mentioned restrictions, but only for class files with version number >= 53(Java 9). For class files with version numbers < 53, restrictions are only partially enforced (as it is done by releases
preceding JDK 9). That is, for class files with version number <
53 final fields can be modified in any method of the class
declaring the field (not only class/instance initializers).
So, you can try compiling your code with source and target 1.8 to check if that resolves the issue for now. This should be doable with --release 8 option using the latest javac tool.
Please read JPA specification - http://download.oracle.com/otndocs/jcp/persistence-2_2-mrel-eval-spec/index.html - Section 2.1 The Entity Class:
The entity class must not be final. No methods or persistent instance variables of the entity class may be final.
Method _persistence_set is code added by weaving (bytecode manipulation of entity classes) and is used to initialize values of entity attributes after class was created by default constructor (with no attributes) call. Java 1.8 allowed this even with final fields, but Java 9 does not.
You should now follow JPA specification and should not put final persistence attributes into your entities.
Eclipselink does not admit it, however, I wanted this for my project. So I did a dirty "hack" to be able to do it. Basically, I have overwritten eclipselink class org.eclipse.persistence.internal.jpa.weaving.ClassWeaver and I have added this method:
#Override
public FieldVisitor visitField(
final int access,
final String name,
final String descriptor,
final String signature,
final Object value) {
if (cv != null) {
int newAccess = access;
if (!Modifier.isStatic(access) && Modifier.isFinal(access)) {
newAccess = access & (~Opcodes.ACC_FINAL);
}
return cv.visitField(newAccess, name, descriptor, signature, value);
}
return null;
}
Which will remove all final modifiers from non static fields on entities when weaving.
I think eclipselink should consider adding this, at least as an option.

??? like function in Scala

https://github.com/scala/scala/blob/2.11.x/src/library/scala/Predef.scala#L230
??? in scala is a function defined in predef that throws a NotImplementedError
In my project I am using Google Guice in order to inject dependencies, and thought it would be good to have a similar function that throws an exception if the injection never happened, in order to catch missing usages of the injector or missing #Inject annotations.
In my project I have a class that is expecting to be injected
class OScoreboard {
#Inject
val source :Provider[ScoreboardBuilder] = injected;
}
and an object
class ExpectedInjectionException(message: String = null, cause: Throwable = null) extends RuntimeException
object injected extends Nothing{
def apply : Nothing = {
throw new ExpectedInjectionException("Expected an injection")
}
}
But I get the error that injected isn't of type Provider[ScoreboardBuilder]
Am I abusing apply? How else can I reference the scala function apply (or even with a different name) without referencing the object injected?
Also I suspect that even if I fix this error, the function will be eagerly run causing the exception before injection happens, does that mean I need to make every injected field lazy, or is there another solution?
Edit:
The problem was my understanding of Scala.
vals are eagerly computed, so the ???-like function is immediately executed on class construction (which since it's using field injection, occurs immediately before injection happens) causing the field to never be injected.
Values like final fields in Java CAN be injected, because it's only a restriction by the byte code verifier. final fields can be written to fine by using reflection (which Guice does).
In order to answer this question there needs to be a way to delay the execution of the ???-like function/value until the field is first read. I'm unsure how, or if it is even possible. The other option is just to initialize them to null. But that will result in NullPointerExceptions which are famously unhelpful. I was hoping to use a null-like error with an explanation that the injection failed.
First of all: in one place you wrote INJECTED and in the other place injected. I'll assume this was a typo and that you mean the same thing with both.
An assignment like this:
val source :Provider[ScoreboardBuilder] = INJECTED;
will not work because you are trying to assign the object INJECTED to a variable of type Provider[ScoreboardBuilder]. The object is not of that type, so you can't do that assignment.
Maybe you expected that the object would behave like a function and that its apply method would automatically be called, but that's not how it works.
You can define INJECTED as a method inside your class:
class OScoreboard {
#Inject
val source :Provider[ScoreboardBuilder] = INJECTED
private def INJECTED : Nothing =
throw new ExpectedInjectionException("Expected an injection")
}
Or you can put it in a separate object, but then you'd have to import it in your class:
object injected {
def INJECTED : Nothing =
throw new ExpectedInjectionException("Expected an injection")
}
class OScoreboard {
import injected._
#Inject
val source :Provider[ScoreboardBuilder] = INJECTED
}
The problem was my understanding of Scala.
vals are eagerly computed, so the ??? function is immediately executed on class construction (which since it's using field injection, occurs immediately before injection happens) causing the exception to be thrown.
Making it lazy results in the injection happening using reflection without the exception being thrown on construction. HOWEVER the generated Java code is not aware that this happens. So when the injected value is accessed for the first time, the generated code replaces the injected reference with ??? then proceeds to throw the exception.
There is no way that I can see in order to make this work.

Way to enforce length check constraint in MyBatis

I have some check constraints defined by SYS schema in DB for a particular column.
Now, while invoking it from Java code through MyBatis, is there anyway to enforce corresponding field length validations through MYBatis configuration only.
PS: I don't want to enforce constraints at VO level (setter individually). Or using JSR 303
DataBase : Oracle 11g
Using MyBatis
If you do not want to validate in your java beans (manually, or using JSR 303) I think you could write your own typeHandler for those field.
Typehandler would handle String fields and do validation.
See code example for String TypeHandler.
You could enforce your validation logic (of any complexity) in handler's get/set methods.
If you want to use TypeHandler to trim string to given length when saving to database, do it in setNonNullParameter method.
Sample code below
#MappedJdbcTypes(JdbcType.VARCHAR)
public class ExampleTypeHandler extends BaseTypeHandler<String> {
#Override
public void setNonNullParameter(PreparedStatement ps, int i,
String parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter.substring(0,DESIRED_MAX_LENGTH));
}
You could also trim (or otherwise modify) values you read from database- you need to modify get* method in your TypeHandler implementation to do that.
You must tell mappers to use your handler. Otherwise, default handler for given type will be used.
Your SQLs in XML file must use syntax
#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}
Check https://mybatis.github.io/mybatis-3/sqlmap-xml.html for details.

Dagger - Inject provide beans both to field variable and constructor at same this

I have a class with the following structure.
Is it "legal" in Dagger to #Inject beans in field variables and constructors at the same time, as I have done below? If no - I have a MyActivityModule and MyApplicationModule, how can I get the dependencies from MyApplicationModule and add them to the constructor I use in the provideWhatEvery in the MyActivityModule ?
#Inject SmsFormatter mSmsFormatter;
#Inject SmsGuardiansUtils smsGuardiansUtils;
#Inject BipperMediaPlayer bipperMediaPlayer;
#Inject MixPanelUtils mMixpanelUtils;
#Inject
public ImHereController(View view, Context context, AlarmModel alarmModel, ActionBarListener actionBarListener,
FragmentController fragmentController){
super(view, context, alarmModel, actionBarListener, fragmentController);
}
You can inject fields and constructors as you have. The constructor parameters will be resolved first and injected upon construction, and after that the fields will be injected.
The other parts of your question are unclear - it doesn't matter whether you add dependencies by field injection or constructor injection - if you wanted to add them all with constructor injection you could.
The only time you must use field injection is where you have an object whose instantiation you cannot control, and therefore dagger cannot itself instantiate (like Activity and Application subtypes.)
All that said, I would not use both without some compelling reason - constructor injection is more semantically clear and you can make the instance variables final. Alternately, field injection is more terse, and possibly more readable in cases. I would pick one, and not both.