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
Related
I have one instance of wiremock that is used across multiple test classes, It has worked fine until recently, when used to test
async methods, when the test classes are ran singly, tests pass but when the entire tests are ran(mvn test), some of the async class tests fail with
ConditionTimeOut error. The verify is failing because, I presume, the wiremock server was not done when the verify was called and the awaitility library is
waiting for it. Just my understanding based on this links -->
https://github.com/tomakehurst/wiremock/issues/565
https://github.com/tomakehurst/wiremock/issues/574
here is my wiremock class def :
#ExtendWith(SpringExtension.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureWireMock(port = 9099)
public class WireMockTest {
#Autowired
public wireMockClassA wireMockClassA;
#Autowired
public wireMockClassB wireMockClassB;
//other definitions here and more wiremock class...
}
here is an example test async class:
public class SaleWireMockTest extends WireMockTest {
#Test
void call_sale_endpoint_and_return_200() {
wireMockClassA.callSaleEndpoint(PATH, request, HttpStatus.OK);
makeAsyncCall();
await().atMost(1, TimeUnit.SECONDS).untilAsserted(() ->
wireMockClassA.verify(1, request));
}
//more test methods here....
}
stack:
java 14
wiremock 2.26.2
Spring boot 2.3.2.RELEASE
Have you tried setting the first poll time?
await().pollDelay(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(3)).untilAsserted(() -> {...});
I was browsing through a lot of articles and blogs to find the proper way to get the following running. I already achived the following:
Spring Boot Application - works
Imperative Spring Data MongoDB Connection to my Mongo Atlas Cluster - works
Spring GraphQL Starter implementation (Resolvers, etc.) - works
Now I want to implement my last requirement. To have GraphQL subscriptions working I need to integrate the Spring Data MongoDB Reactive dependency and create a new GraphQL Resolver for Subscriptions. Here is the code that I added to the already working app (hopefully the code fragments give enough info to help me out).
Gradle.kt
implementation("org.springframework.boot:spring-boot-starter-data-mongodb-reactive")
MyApp.kt
#SpringBootApplication
#EnableReactiveMongoRepositories(basePackages = ["com.myapp"])
#EnableMongoRepositories(basePackages = ["com.myapp"])
class MyApp
fun main(args: Array<String>) {
runApplication<MyApp>(*args)
}
SubscriptionResolver.kt
#Component
class SubscriptionResolver(
private val characterReactiveRepository: CharacterReactiveRepository
) : GraphQLSubscriptionResolver {
fun allCharacters(): Flux<Character> {
return characterReactiveRepository.findAll()
}
}
CharacterReactiveRepository.kt
interface CharacterReactiveRepository : ReactiveMongoRepository<Character, String>
character.graphqls
type Subscription {
allCharacters: [Character]!
}
Error
SchemaClassScannerError: Unable to match type definition (NonNullType{type=ListType{type=TypeName{name='Character'}}}) with java type (reactor.core.publisher.Flux<com.backend.domain.Character>): Java class is not a List or generic type information was lost: reactor.core.publisher.Flux<com.backend.domain.Character>
Detailed Exception
https://pastebin.com/sEWmDaTE
Edit 1
#Component
class SubscriptionResolver(
private val characterReactiveRepository: CharacterReactiveRepository
) : GraphQLSubscriptionResolver {
fun allCharacters(): Publisher<Character> {
return characterReactiveRepository.findAll()
}
}
According to the sample, you should return:
#Component
class SubscriptionResolver(
private val characterReactiveRepository: CharacterReactiveRepository
) : GraphQLSubscriptionResolver {
fun allCharacters(): Publisher<List<Character>> {
return characterReactiveRepository.findAll()
}
}
Example application you can find here https://github.com/graphql-java-kickstart/samples/tree/master/spring-boot-webflux
My problem was that I defined the subscription's method's return value as [Character]! meaning an array. But since Flux<Character> or Publisher<Character> is not an array but a single type in that context the resolving failed all the time.
Changing the schema to the following helped:
type Subscription {
allCharacters: Character
}
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.
Clarification
This questions was asked before kotlin hit version 1.0. Language syntax in example is obsolete now, please follow official docs.
I'm playing with kotlin and spring DI.
I want to use constructor-based dependency injection, so I need to annotate the constructor.
I tried following approach:
Configuration
Import(javaClass<DataSourceConfig>())
public open class AppConfig(dataSource: DataSource) {
private val dataSource: DataSource
Autowired {
this.dataSource = dataSource
}
}
Configuration
public open class DataSourceConfig {
Bean
public open fun dataSource(): DataSource {
// source omitted
}
}
But it doesn't work. Is it even possible to annotate constructor in kotlin?
P.S. I'm using Kotlin M10.1 and Spring 4.1.4
UPDATE:
Annotating constructor is possible in kotlin. The problem was that it's not allowed to use constructor-based DI for #Configuration
Hrm, I think the syntax has changed radically since this question was posted. The current way (according to the docs) is to add the keyword constructor between your class name and arguments and annotate that, i.e.
public class AppConfig #Configuration constructor(dataSource: DataSource) {
//...
}
Try to write:
Configuration
public open class AppConfig [Import(javaClass<DataSourceConfig>())] (dataSource: DataSource) {
//...
}
This syntax works for me:
Configuration
Import(javaClass<DataSourceConfig>())
public open class AppConfig {
private val dataSource: DataSource
Autowired constructor(dataSource: DataSource){
this.dataSource = dataSource
}
}
I'm trying to add a custom GORM event listener class in Bootstrap.groovy, as described in the Grails documentation but its not working for me. Here is the code straight from the docs:
def init = {
application.mainContext.eventTriggeringInterceptor.datastores.each { k, datastore ->
applicationContext.addApplicationListener new MyPersistenceListener(datastore)
}
}
When I run it, the compiler complains that application and applicationContext are null. I've tried adding them as class level members but they don't get magically wired up service-style. The closest I've got so far is:
def grailsApplication
def init = { servletContext ->
def applicationContext = servletContext.getAttribute(ApplicationAttributes.APPLICATION_CONTEXT)
grailsApplication.mainContext.eventTriggeringInterceptor.datastores.each { k, datastore ->
applicationContext.addApplicationListener new GormEventListener(datastore)
}
}
But I still get errors: java.lang.NullPointerException: Cannot get property 'datastores' on null object.
Thanks for reading...
EDIT: version 2.2.1
If you do:
ctx.getBeansOfType(Datastore).values().each { Datastore d ->
ctx.addApplicationListener new MyPersistenceListener(d)
}
This should work without needing the Hibernate plugin installed
That looks like it should work, although I'd do it a bit differently. BootStrap.groovy does support dependency injection, so you can inject the grailsApplication bean, but you can also inject eventTriggeringInterceptor directly:
class BootStrap {
def grailsApplication
def eventTriggeringInterceptor
def init = { servletContext ->
def ctx = grailsApplication.mainContext
eventTriggeringInterceptor.datastores.values().each { datastore ->
ctx.addApplicationListener new MyPersistenceListener(datastore)
}
}
}
Here I still inject grailsApplication but only because I need access to the ApplicationContext to register listeners. Here's my listener (simpler than what the docs claim the simplest implementation would be btw ;)
import org.grails.datastore.mapping.core.Datastore
import org.grails.datastore.mapping.engine.event.AbstractPersistenceEvent
import org.grails.datastore.mapping.engine.event.AbstractPersistenceEventListener
class MyPersistenceListener extends AbstractPersistenceEventListener {
MyPersistenceListener(Datastore datastore) {
super(datastore)
}
protected void onPersistenceEvent(AbstractPersistenceEvent event) {
println "Event $event.eventType $event.entityObject"
}
boolean supportsEventType(Class eventType) { true }
}
Finally stumbled onto a working Bootstrap.groovy, thanks to this post but I don't think its the best way to do it, rather its a work around.
def init = { servletContext ->
def applicationContext = servletContext.getAttribute(ApplicationAttributes.APPLICATION_CONTEXT)
applicationContext.addApplicationListener new GormEventListener(applicationContext.mongoDatastore)
}
So basically I'm hard-coding the MongoDB datastore directly as opposed to iterating over the available ones, as the docs suggest.
To save you reading the comments to the first answer, the adapted version I provided in the Question (as well as Burt's answer) only works if the Hibernate plugin is installed but in my case I was using the MongoDB plugin so had no need for the Hibernate plugin (it in fact broke my app in other ways).