In Java I can do following thing:
String table = Foo.class.getAnnotation(Table.class).name();
How can I archive this in Scala? Even annotations defined in Java do not seem to have those "name()" methods ...
This should do the trick:
val table = classOf[Foo].getAnnotation(classOf[Table]).name()
That works if you have something like this:
#java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
#java.lang.annotation.Target({java.lang.annotation.ElementType.ANNOTATION_TYPE})
public #interface Table {
public String name();
}
This is the annotation definition that should exist in a Java source file.
And the Foo class:
#Table(name="hello")
class Foo {
}
Related
I want to write an annotation with members in PlantUML. Specifically, I want to describe this Java code in PlantUML:
public #interface Foo {
String bar();
String baz();
}
I tried to write it in PlantUML, but it causes syntax error:
#startuml
annotation Foo {
String bar()
String baz()
}
#enduml
However, it's working when I omit the members:
#startuml
annotation Foo
#enduml
What should I do? Thanks.
In PlantUML, annotations can not have members (hence the syntax error).
To display a UML diagram for your code, you will need to use another solution, like adding the annotation as a separate entity:
#startuml
annotation interface
class Foo {
String bar();
String baz();
}
interface -- Foo
#enduml
Or include the annotation in the class name definition:
#startuml
class "#interface Foo" as Foo {
String bar();
String baz();
}
#enduml
It's possible to write annotations with members now: http://www.plantuml.com/plantuml/uml/SoWkIImgAStDuKhCoyilIIp9pCzJSClFLwZcKW22u9AYpBnqXQJ48WrDL84ge40jbqDgNWfGCm00
According to the comment, it's available starting at version V1.2020.2.
Is there any sample Scala code available for creating stored procedures in Neo4j-3.0.3 ?
I have been trying to create one simple Scala based stored procedure. Below is the Error message I get when I copy my scala-jar file to the neo4j-plugins directory and start the neo4j server :
=================
Caused by: org.neo4j.kernel.lifecycle.LifecycleException: Component 'org.neo4j.kernel.impl.proc.Procedures#1ac0223' was successfully initialized, but failed to start. Please see attached cause exception.
at org.neo4j.kernel.lifecycle.LifeSupport$LifecycleInstance.start(LifeSupport.java:444)
at org.neo4j.kernel.lifecycle.LifeSupport.start(LifeSupport.java:107)
at org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory.newFacade(GraphDatabaseFacadeFactory.java:140)
... 10 more
Caused by: org.neo4j.kernel.api.exceptions.ProcedureException: Unable to find a usable public no-argument constructor in the class `neoscala`. Please add a valid, public constructor, recompile the class and try again.
=================
The scala class that I have used is :
package neoproc
import org.neo4j.graphdb.GraphDatabaseService
import org.neo4j.procedure.Procedure;
import javax.ws.rs.core.{Context, Response}
class neoscala(#Context db: GraphDatabaseService) {
#Procedure
def alice():String = {
String.valueOf(db.execute( "MATCH (n:User) return n" ));
}
}
Your Scala class declares a constructor with a GraphDatabaseService argument, and the exception tells you that it only wants a no-argument constructor.
It's documented in both
the user documentation:
Only static fields and #Context-annotated fields are allowed in Procedure classes.
the Javadoc:
The procedure method itself can contain arbitrary Java code - but in order to work with the underlying graph, it must have access to the graph API. This is done by declaring fields in the procedure class, and annotating them with the Context annotation. Fields declared this way are automatically injected with the requested resource. This is how procedures gain access to APIs to do work with.
All fields in the class containing the procedure declaration must either be static; or it must be public, non-final and annotated with Context.
Apparently it's not possible to create a class with a public field in Scala, so you'll have to create a parent Java class with the public field, and extend it with your Scala class:
// ProcedureAdapter.java
public abstract class ScalaProcedureAdapter {
#Context
public GraphDatabaseService db;
}
// neoscala.scala
class neoscala extends ScalaProcedureAdapter {
// ...
}
Here is the solution for this :
We will create Class in scala :
class FullTextIndex extends JavaHelper {
#Procedure("example.search")
#PerformsWrites
def search(#Name("label") label: String,
#Name("query") query: String): Stream[SearchHit] = {
//declare your method
}
val nodes: Stream[Node] = db.index.forNodes(index).query(query).stream
val newFunction: java.util.function.Function[Node, SearchHit] = (node: Node) => new SearchHit(node)
nodes.map {
newFunction
}
}
private def indexName(label: String): String = {
"label-" + label
}
}
Procedure in Neo4j always return result in Stream and it is a latest feature in Java8 so we will also used Java Class for return the final result and For defining the public variable.
We will create Java class for result :
public class JavaHelper {
#Context
public GraphDatabaseService db;
#Context
public Log log;
public static class SearchHit {
//your result code here
}
You can refer knoldus blog for Neo4j User Defined Procedure for creating and storing Neo4j Procedure with Scala. Here you will also find sample code with git hub repository.
I'm using Spring AOP to intercept a method execution.
I have an interface that looks like the following:
public interface MyAwesomeService {
public Response doThings(int id, #AwesomeAnnotation SomeClass instance);
}
Here is the implementation of the interface:
public class MyAwesomeServiceImpl implements MyAwesomeService {
public Response doThings(int id, SomeClass instance) {
// do something.
}
}
Now i would like any method which has a parameter annotated with #AwesomeAnnotation should be captured by Spring AOP.
So I wrote the following aspect which works.
#Aspect
#Component
public class MyAwesomeAspect {
#Around("myPointcut()")
public Object doAwesomeStuff(final ProceedingJoinPoint proceedingJoinPoint) {
final MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
Annotation[][] annotationMatrix = methodSignature.getMethod().getParameterAnnotations();
// annotationMatrix is empty.
}
#Pointcut("execution(public * *(.., #package.AwesomeAnnotation (package.SomeClass), ..))")
public void myPointcut() {}
}
However when I try to find the parameter annotations I don't get any annotations back. As mentioned above, the annotationMatrix is empty.
So here are my questions:
Why is the annotationMatrix empty? Probably because parameter annotations are not inherited from an interface.
Why I'm able to capture the method execution. Since Spring AOP is able match the pointcut, Spring somehow is able to see the method's parameter annotations but when I try to see that using methodSignature.getMethod().getParameterAnnotations() it doesn't work.
I also faced this issue with one of my parameter annotations. I was able to fix the same by making sure that the parameter annotation definition had RetentionPolicy as RUNTIME and Target as PARAMETER
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PARAMETER)
public #interface Param {
public String name();
}
The answers to your questions:
Parameter annotations are not inherited from interfaces to implementing methods. In fact, annotations are almost never inherited, only from class (not interface!) to subclass if the annotation type itself is annotated by #Inherited, see JDK API documentation.
Update: Because I have answered this question several times before, I have just documented the problem and also a workaround in Emulate annotation inheritance for interfaces and methods with AspectJ.
Because during compile or weave time AspectJ can match your pointcut against the interface method and thus sees the annotation.
You can fix the situation by adding the annotation to the parameter in your interface implementation, e.g. like this:
#Override
public Response doThings(int id, #AwesomeAnnotation SomeClass instance) {
// ...
}
Then with an aspect like this...
#Aspect
#Component
public class MyAwesomeAspect {
#Pointcut("execution(public * *..MyAwesomeService.*(*, #*..AwesomeAnnotation (*), ..)) && args(*, instance, ..)")
static void myPointcut(SomeClass instance) {}
#Around("myPointcut(instance)")
public Object doAwesomeStuff(Object instance, ProceedingJoinPoint proceedingJoinPoint) {
System.out.println(proceedingJoinPoint);
System.out.println(" instance = " + instance);
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
Annotation[][] annotationMatrix = methodSignature.getMethod().getParameterAnnotations();
for (Annotation[] annotations : annotationMatrix) {
for (Annotation annotation : annotations) {
System.out.println(" annotation = " + annotation);
}
}
return proceedingJoinPoint.proceed();
}
}
... you get a console log similar to this:
execution(Response de.scrum_master.app.MyAwesomeServiceImpl.doThings(int, SomeClass))
instance = de.scrum_master.app.SomeClass#23fc625e
annotation = #de.scrum_master.app.AwesomeAnnotation()
I have 3 java files: HW.java, myAnn.java, and Constants.java in package myApp.
Constants.java:
public final class Constants {
public static final String WORLD ="World";
}
myAnn.java:
public #interface myAnn {
java.lang.String name() default "";
}
HW.java:
class HW {
#myAnn(name = Constants.WORLD)
public static void main(String[] args){
System.out.println("Hi "+ Constants.WORLD);
}
}
My app compiles and runs fine as shown above, but I want to migrate HW.java to scala as
HelloWorld.scala:
object HelloWorld {
#myAnn(name = Constants.WORLD)
def main(args: Array[String]) {
println("Hello " + Constants.WORLD)
}
}
When I try to compile this, I get
error: annotation argument needs to be a constant; found:
Constants.WORLD #myAnn(name = Constants.WORLD)
If I remove the annotation then HelloWorld compiles and executes as expected.
Why can I use Constants.WORLD as a parameter to an annotation from a java program, but not from a scala program? Is there something I can modify in Constants.java to allow it to be used from either java or scala? I can't modify MyAnn.java, and I can't migrate Constants.java yet.
It is a bug that only shows up when feeding the java source files into the scala compiler, see issue SI-2764. The example works when compiling the java files first using javac and then pointing scalac's classpath to the generated classfiles.
Is there a way to call a method in a Grails service, from a Scala class that is running on the same JVM?
I have seen something similar done from Groovy/Griffon but cannot figure out how to accomplish that in Grails. (http://www.jroller.com/aalmiray/entry/griffon_groovy_scala_working_together)
Basically, one of my Grails controllers calls some Scala code, which should return some values asynchronously. So, I guess, the only way to return those values is by calling back a method in a Grails service.
I found a way of doing it, inspired by the link in the question above, and one of the FAQs in the Grails website.
On the Scala side:
Declare an object similar to the following:
package scalaCallback
object ScalaCallback{
var cback: {def callback(example: String)} = null
def setCallback(cb: {def callback(example: String)}){
cback = cb
}
def invokeCallback(example: String){
if(callback != null) cback.callback(example)
}
}
On the Grails side:
Create a class in src/groovy similar to the following:
package groovyCallback
import org.codehaus.groovy.grails.commons.ApplicationHolder
class GroovyCallback{
private GroovyCallback() {}
private static final INSTANCE = new GroovyCallback()
static getInstance(){ return INSTANCE }
void callback(String example){
ApplicationHolder.application.mainContext.yourService.yourMethod(example)
}
}
In your BootStrap.groovy init add the following:
scalaCallback.cback = groovyCallback.GroovyCallback.getInstance()
When you call invokeCallback("example") in Scala, it will call yourService.yourMethod("example")
Note: the jar file with your Scala class should be in the lib folder of you Grails application
Your Grails service is a Spring bean. #Autowire the service into your Scala class (it will need to be a bean/#Component) and call the method.
EDIT - added example:
For example (using Java, not Scala but the approach is exactly the same):
Java code calling service:
package grailstest;
#Component
public class ServiceInjectionTester {
#Autowired TestService testService;
public String testTheService() {
return testService.serviceMethod();
}
}
Service:
class TestService {
String serviceMethod() {
return "success"
}
}
In Config.groovy:
grails.spring.bean.packages = [ "grailstest" ]
You can also wire your Java/Scala bean into your Grails classes:
class TestController {
#Autowired
ServiceInjectionTester serviceInjectionTester
def index = {
render(text: serviceInjectionTester.testTheService())
}
}
References:
Grails Reference 8.4 - Using Services from Java
Spring: The Foundation for Grails