Proto + Kafka Producer: Error serializing object to JSON: Direct self-reference leading to cycle (through reference chain unknownFields - apache-kafka

Stack: Micronaut-Kafka, Proto3, gRPC, BloomRPC
Goal: reiceve a grpc request from BloomRPC and post it to a kafka topic
Context: I coded a gRPC endpoint which receives a simple call successfully but when trying to post such object to Kafka topic I get
12:38:18.775 [DefaultDispatcher-worker-1] ERROR i.m.r.intercept.RecoveryInterceptor - Type [com.mybank.producer.DebitProducer$Intercepted] executed with error: Exception sending producer record for method [void sendRequestMessage(String key,DebitRequest message)]: Error serializing object to JSON: Direct self-reference leading to cycle (through reference chain: com.mybank.endpoint.DebitRequest["unknownFields"]->com.google.protobuf.UnknownFieldSet["defaultInstanceForType"])
io.micronaut.messaging.exceptions.MessagingClientException: Exception sending producer record for method [void sendRequestMessage(String key,DebitRequest message)]: Error serializing object to JSON: Direct self-reference leading to cycle (through reference chain: com.mybank.endpoint.DebitRequest["unknownFields"]->com.google.protobuf.UnknownFieldSet["defaultInstanceForType"])
at io.micronaut.configuration.kafka.intercept.KafkaClientIntroductionAdvice.wrapException(KafkaClientIntroductionAdvice.java:564)
I guess somehow my issue is related to "...Error serializing object to JSON". Do I really have to convert such object to json? Can I not just post it to kafka topic? What I am missing here? Well, I can easily fix this issue by creating a new object and setting each property to it accordingly to the request object like this:
endpoint (controller) method
override suspend fun sendDebit(request: DebitRequest): DebitReply {
var dtoDebiter: Debiter = Debiter()
dtoDebiter.id = request.id.toString()
dtoDebiter.name = request.name
transactionService.postDebitTransaction(dtoDebiter)
return DebitReply.newBuilder().setMessage(postStatus).build()
}
Model created only for conversion (doesn't seem weird this solution???)
class Debiter {
lateinit var id: String
lateinit var name: String
}
So, my straight question is: can I reuse the same autogenerated stub resulted from the proto file as a model both for receiving the request and posting it to kafka topic? If so, what is wrong in code bellow? If not, what is the recommended approach?
Full code:
transaction.proto
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.mybank.endpoint";
option java_outer_classname = "TransactionProto";
option objc_class_prefix = "HLW";
package com.mybank.endpoint;
service Account {
rpc SendDebit (DebitRequest) returns (DebitReply) {}
}
message DebitRequest {
int64 id = 1;
string name = 2;
}
message DebitReply {
string message = 1;
}
transaction endpoint (controller)
package com.mybank.endpoint
import com.mybank.dto.Debiter
import com.mybank.service.TransactionService
import javax.inject.Singleton
#Singleton
#Suppress("unused")
class TransactionEndpoint(val transactionService: TransactionService) : AccountGrpcKt.AccountCoroutineImplBase(){
override suspend fun sendDebit(request: DebitRequest): DebitReply {
var postStatus: String = transactionService.postDebitTransaction(request)
return DebitReply.newBuilder().setMessage(postStatus).build()
}
}
transaction service (not really relevant here)
package com.mybank.service
import com.mybank.dto.Debiter
import com.mybank.dto.Transaction
import com.mybank.dto.Transactions
import com.mybank.endpoint.DebitRequest
import com.mybank.producer.DebitProducer
import javax.inject.Inject
import javax.inject.Named
import javax.inject.Singleton
#Singleton
class TransactionService(){
#Inject
#Named("debitProducer")
lateinit var debitProducer : DebitProducer
fun postDebitTransaction(debit: DebitRequest) : String{
debitProducer.sendRequestMessage ("1", debit)
return "posted"
}
}
kafka producer
package com.mybank.producer
import com.mybank.dto.Transaction
import com.mybank.dto.Transactions
import com.mybank.endpoint.DebitRequest
import io.micronaut.configuration.kafka.annotation.KafkaClient
import io.micronaut.configuration.kafka.annotation.KafkaKey
import io.micronaut.configuration.kafka.annotation.Topic
#KafkaClient
public interface DebitProducer {
#Topic("debit")
fun sendRequestMessage(#KafkaKey key: String?, message: DebitRequest?) {
}
}
build.gradle
plugins {
id "org.jetbrains.kotlin.jvm" version "1.3.72"
id "org.jetbrains.kotlin.kapt" version "1.3.72"
id "org.jetbrains.kotlin.plugin.allopen" version "1.3.72"
id "application"
id 'com.google.protobuf' version '0.8.13'
}
version "0.2"
group "account-control"
repositories {
mavenLocal()
jcenter()
}
configurations {
// for dependencies that are needed for development only
developmentOnly
}
dependencies {
kapt(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion"))
kapt("io.micronaut:micronaut-inject-java")
kapt("io.micronaut:micronaut-validation")
implementation(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion"))
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}")
implementation("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion")
implementation("io.micronaut:micronaut-runtime")
// implementation("io.micronaut.grpc:micronaut-grpc-runtime")
implementation("io.micronaut.grpc:micronaut-grpc-server-runtime:$micronautGrpcVersion")
implementation("io.micronaut.grpc:micronaut-grpc-client-runtime:$micronautGrpcVersion")
implementation("io.grpc:grpc-kotlin-stub:${grpcKotlinVersion}")
//Kafka
implementation("io.micronaut.kafka:micronaut-kafka")
//vertx
implementation("io.micronaut.sql:micronaut-vertx-mysql-client")
//implementation("io.micronaut.configuration:micronaut-vertx-mysql-client")
compile 'io.vertx:vertx-lang-kotlin:3.9.4'
//mongodb
implementation("org.mongodb:mongodb-driver-reactivestreams:4.1.1")
runtimeOnly("ch.qos.logback:logback-classic:1.2.3")
runtimeOnly("com.fasterxml.jackson.module:jackson-module-kotlin:2.9.8")
kaptTest("io.micronaut:micronaut-inject-java")
testImplementation enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.3.0")
testImplementation("io.micronaut.test:micronaut-test-junit5")
testImplementation("org.mockito:mockito-junit-jupiter:2.22.0")
testRuntime("org.junit.jupiter:junit-jupiter-engine:5.3.0")
testRuntime("org.jetbrains.spek:spek-junit-platform-engine:1.1.5")
}
test.classpath += configurations.developmentOnly
mainClassName = "account-control.Application"
test {
useJUnitPlatform()
}
allOpen {
annotation("io.micronaut.aop.Around")
}
compileKotlin {
kotlinOptions {
jvmTarget = '11'
//Will retain parameter names for Java reflection
javaParameters = true
}
}
//compileKotlin.dependsOn(generateProto)
compileTestKotlin {
kotlinOptions {
jvmTarget = '11'
javaParameters = true
}
}
tasks.withType(JavaExec) {
classpath += configurations.developmentOnly
jvmArgs('-XX:TieredStopAtLevel=1', '-Dcom.sun.management.jmxremote')
}
sourceSets {
main {
java {
srcDirs 'build/generated/source/proto/main/grpc'
srcDirs 'build/generated/source/proto/main/grpckt'
srcDirs 'build/generated/source/proto/main/java'
}
}
}
protobuf {
protoc { artifact = "com.google.protobuf:protoc:${protocVersion}" }
plugins {
grpc { artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}" }
grpckt { artifact = "io.grpc:protoc-gen-grpc-kotlin:${grpcKotlinVersion}" }
}
generateProtoTasks {
all()*.plugins {
grpc {}
grpckt {}
}
}
}
in case it is relevant, here is a piece of the stub autogenerated by proto
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: transaction.proto
package com.mybank.endpoint;
/**
* Protobuf type {#code com.mybank.endpoint.DebitRequest}
*/
public final class DebitRequest extends
com.google.protobuf.GeneratedMessageV3 implements
// ##protoc_insertion_point(message_implements:com.mybank.endpoint.DebitRequest)
DebitRequestOrBuilder {
private static final long serialVersionUID = 0L;
// Use DebitRequest.newBuilder() to construct.
private DebitRequest(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
super(builder);
}
private DebitRequest() {
name_ = "";
}
#java.lang.Override
#SuppressWarnings({"unused"})
protected java.lang.Object newInstance(
UnusedPrivateParameter unused) {
return new DebitRequest();
}
#java.lang.Override
public final com.google.protobuf.UnknownFieldSet
getUnknownFields() {
return this.unknownFields;
}
private DebitRequest(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
this();
...
*** First edition
#KafkaClient(
id="debit-client",
acks = KafkaClient.Acknowledge.ALL,
properties = [Property(name = ProducerConfig.RETRIES_CONFIG, value = "5")]
//How add these two properties in order to use Protobuf Serializer
//kafka.producers.*.key-serializer
//kafka.producers.*.value-serializer
)
public interface DebitProducer {
#Topic("debit")
fun sendRequestMessage(#KafkaKey key: String?, message: DebitRequest?) {
}
*** Second Edition
I tried added the serializer via application.yaml
micronaut:
application:
name: account-control
grpc:
server:
port: 8082
kafka:
producers:
product-client:
value:
serializer: io.confluent.kafka.serializers.protobuf.KafkaProtobufSerializer
gradle.build
//kafka-protobuf-serializer
implementation("io.confluent:kafka-protobuf-serializer:6.0.0")
and now I get during gradle build
Execution failed for task ':extractIncludeProto'.
> Could not resolve all files for configuration ':compileProtoPath'.
> Could not resolve com.squareup.wire:wire-schema:3.2.2.
Required by:
project : > io.confluent:kafka-protobuf-serializer:6.0.0 > io.confluent:kafka-protobuf-provider:6.0.0
> The consumer was configured to find a component, preferably only the resources files. However we cannot choose between the following variants of com.squareup.wire:wire-schema:3.2.2:
- jvm-api
- jvm-runtime
- metadata-api
All of them match the consumer attributes:
- Variant 'jvm-api' capability com.squareup.wire:wire-schema:3.2.2 declares a component, packaged as a jar:
- Unmatched attributes:
- Provides release status but the consumer didn't ask for it
- Provides an API but the consumer didn't ask for it
- Provides attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm' but the consumer didn't ask for it
- Variant 'jvm-runtime' capability com.squareup.wire:wire-schema:3.2.2 declares a component, packaged as a jar:
- Unmatched attributes:
- Provides release status but the consumer didn't ask for it
- Provides a runtime but the consumer didn't ask for it
- Provides attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm' but the consumer didn't ask for it
- Variant 'metadata-api' capability com.squareup.wire:wire-schema:3.2.2:
- Unmatched attributes:
- Doesn't say anything about its elements (required them preferably only the resources files)
- Provides release status but the consumer didn't ask for it
- Provides a usage of 'kotlin-api' but the consumer didn't ask for it
- Provides attribute 'org.jetbrains.kotlin.platform.type' with value 'common' but the consumer didn't ask for it
* Try:
Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':extractIncludeProto'.
at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:38)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:416)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:406)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:102)
at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:41)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:370)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:357)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:350)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:336)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:127)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:191)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:182)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:124)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
Caused by: org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration$ArtifactResolveException: Could not resolve all files for configuration ':compileProtoPath'.
at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.rethrowFailure(DefaultConfiguration.java:1265)
at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.access$1800(DefaultConfiguration.java:141)
at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$ConfigurationFileCollection.visitContents(DefaultConfiguration.java:1242)
at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$ConfigurationFileCollection.visitContents(DefaultConfiguration.java:1235)
at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.visitContents(DefaultConfiguration.java:489)
at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:265)
at org.gradle.api.internal.file.CompositeFileCollection.visitContents(CompositeFileCollection.java:152)
at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:265)
at org.gradle.internal.fingerprint.impl.DefaultFileCollectionSnapshotter.snapshot(DefaultFileCollectionSnapshotter.java:50)
at org.gradle.internal.fingerprint.impl.AbstractFileCollectionFingerprinter.fingerprint(AbstractFileCollectionFingerprinter.java:47)
at ...
ultPlanExecutor.java:182)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:124)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)

Related

Problems with database connection Ktor!!! I just don't understand why the ktor not to see the path of application.conf jbdc

I'm having a problem with my web project. It is my first time when i try connecting database. I want to connect database to see that working. I use Postgres and have set up a database. I want to connect by using the following code :
Data base settings
package com.testreftul
import com.testreftul.model.Orders
import com.testreftul.model.Products
import com.testreftul.model.User
import com.typesafe.config.ConfigFactory
import io.ktor.server.config.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.SchemaUtils
import org.jetbrains.exposed.sql.transactions.transaction
object DbSettings {
private val appConfig = HoconApplicationConfig(ConfigFactory.load())
private var dbUrl = appConfig.property("jbdc.url").getString()
private var dbUser = appConfig.property("jbdc.username").getString()
private var dbPassword = appConfig.property("jbdc.password").getString()
fun init(dbUrl: String, dbUser: String, dbPassword: String) {
this.dbUrl = dbUrl
this.dbUser = dbUser
this.dbPassword = dbPassword
pgConnection()
transaction {
SchemaUtils.create(User, Products, Orders)
}
}
private fun pgConnection() = Database.connect(
url = dbUrl,
driver = "org.postgresql.Driver",
user = dbUser,
password = dbPassword
)
suspend fun <T> dbQuery(block:()->T): T =
withContext(Dispatchers.IO){
transaction {
block()
}
}
}
Database plugin
package com.testreftul.plugins
import com.testreftul.DbSettings
import io.ktor.server.application.*
fun Application.connectDatabase(){
val url = environment.config.property("jdbc.url").getString()
val username = environment.config.property("jdbc.username").getString()
val password = environment.config.property("jdbc.password").getString()
DbSettings.init(url,username,password)
}
Application.conf
ktor {
deployment {
port = 8080
port = ${?PORT}
}
application {
modules = [ com.testreftul.ApplicationKt.module ]
}
}
jdbc{
url = "jdbc:postgresql://localhost:5432/restest"
username = "postgres"
password = "admin"
}
build.gradle.kts
val ktor_version: String by project
val kotlin_version: String by project
val logback_version: String by project
val exposed_version:String by project
val postgresql_jdbc:String by project
plugins {
application
kotlin("jvm") version "1.6.20"
id("org.jetbrains.kotlin.plugin.serialization") version "1.6.20"
}
group = "com.testreftul"
version = "0.0.1"
application {
mainClass.set("io.ktor.server.netty.EngineMain")
val isDevelopment: Boolean = project.ext.has("development")
applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment")
}
repositories {
mavenCentral()
maven { url = uri("https://maven.pkg.jetbrains.space/public/p/ktor/eap") }
}
dependencies {
implementation("io.ktor:ktor-server-core-jvm:$ktor_version")
implementation("io.ktor:ktor-server-content-negotiation-jvm:$ktor_version")
implementation("io.ktor:ktor-serialization-kotlinx-json-jvm:$ktor_version")
implementation("io.ktor:ktor-server-netty-jvm:$ktor_version")
implementation("ch.qos.logback:logback-classic:$logback_version")
implementation ("org.jetbrains.exposed:exposed-core:$exposed_version")
implementation ("org.jetbrains.exposed:exposed-dao:$exposed_version")
implementation ("org.jetbrains.exposed:exposed-jdbc:$exposed_version")
implementation ("org.jetbrains.exposed:exposed-java-time:$exposed_version")
implementation ("org.postgresql:postgresql:$postgresql_jdbc")
testImplementation("io.ktor:ktor-server-tests-jvm:$ktor_version")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
}
gradle.properties
ktor_version=2.0.0-beta-1
kotlin_version=1.6.20
logback_version=1.2.3
kotlin.code.style=official
exposed_version=0.37.3
postgresql_jdbc=42.3.3
Application.kt
package com.testreftul
import io.ktor.server.application.*
import com.testreftul.plugins.*
fun main(args: Array<String>): Unit =
io.ktor.server.netty.EngineMain.main(args)
#Suppress("unused") // application.conf references the main function. This annotation prevents the IDE from marking it as unused.
fun Application.module() {
connectDatabase()
configureRouting()
configureSerialization()
}
I installed all the plugins that were needed and created a database,and also i configure my ide and connect to database with dialect postgres.When i run the console return Caused by: io.ktor.server.config.ApplicationConfigurationException: Property jbdc.url not found.
> Task :run FAILED
2022-04-06 01:55:22.805 [main] TRACE Application - {
# application.conf # file:/C:/Users/eljan/IdeaProjects/ktor-restful1/build/resources/main/application.conf: 6
"application" : {
# application.conf # file:/C:/Users/eljan/IdeaProjects/ktor-restful1/build/resources/main/application.conf: 7
"modules" : [
# application.conf # file:/C:/Users/eljan/IdeaProjects/ktor-restful1/build/resources/main/application.conf: 7
"com.testreftul.ApplicationKt.module"
]
},
# application.conf # file:/C:/Users/eljan/IdeaProjects/ktor-restful1/build/resources/main/application.conf: 2
"deployment" : {
# application.conf # file:/C:/Users/eljan/IdeaProjects/ktor-restful1/build/resources/main/application.conf: 3
"port" : 8080
},
# Content hidden
"security" : "***"
}
2022-04-06 01:55:22.976 [main] INFO Application - Autoreload is disabled because the development mode is off.
Exception in thread "main" java.lang.ExceptionInInitializerError
at com.testreftul.plugins.DatabaseKt.connectDatabase(Database.kt:11)
at com.testreftul.ApplicationKt.module(Application.kt:11)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at kotlin.reflect.jvm.internal.calls.CallerImpl$Method.callMethod(CallerImpl.kt:97)
at kotlin.reflect.jvm.internal.calls.CallerImpl$Method$Static.call(CallerImpl.kt:106)
at kotlin.reflect.jvm.internal.KCallableImpl.call(KCallableImpl.kt:108)
at kotlin.reflect.jvm.internal.KCallableImpl.callDefaultMethod$kotlin_reflection(KCallableImpl.kt:159)
at kotlin.reflect.jvm.internal.KCallableImpl.callBy(KCallableImpl.kt:112)
at io.ktor.server.engine.internal.CallableUtilsKt.callFunctionWithInjection(CallableUtils.kt:119)
at io.ktor.server.engine.internal.CallableUtilsKt.executeModuleFunction(CallableUtils.kt:36)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading$launchModuleByName$1.invoke(ApplicationEngineEnvironmentReloading.kt:333)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading$launchModuleByName$1.invoke(ApplicationEngineEnvironmentReloading.kt:332)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.avoidingDoubleStartupFor(ApplicationEngineEnvironmentReloading.kt:357)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.launchModuleByName(ApplicationEngineEnvironmentReloading.kt:332)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.access$launchModuleByName(ApplicationEngineEnvironmentReloading.kt:32)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading$instantiateAndConfigureApplication$1.invoke(ApplicationEngineEnvironmentReloading.kt:313)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading$instantiateAndConfigureApplication$1.invoke(ApplicationEngineEnvironmentReloading.kt:311)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.avoidingDoubleStartup(ApplicationEngineEnvironmentReloading.kt:339)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.instantiateAndConfigureApplication(ApplicationEngineEnvironmentReloading.kt:311)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.createApplication(ApplicationEngineEnvironmentReloading.kt:144)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.start(ApplicationEngineEnvironmentReloading.kt:278)
at io.ktor.server.netty.NettyApplicationEngine.start(NettyApplicationEngine.kt:183)
at io.ktor.server.netty.EngineMain.main(EngineMain.kt:26)
Caused by: io.ktor.server.config.ApplicationConfigurationException: Property jbdc.url not found.
at io.ktor.server.config.HoconApplicationConfig.property(HoconApplicationConfig.kt:15)
at com.testreftul.DbSettings.<clinit>(DbSettings.kt:16)
... 26 more
Caused by: io.ktor.server.config.ApplicationConfigurationException: Property jbdc.url not found.
Execution failed for task ':run'.
> Process 'command 'C:\Users\eljan\.jdks\corretto-16.0.2\bin\java.exe'' finished with non-zero exit value 1
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
You have a typo in config's property names in the definition of default values for private variables. It should be jdbc instead of jbdc:
private var dbUrl = appConfig.property("jbdc.url").getString()
private var dbUser = appConfig.property("jbdc.username").getString()
private var dbPassword = appConfig.property("jbdc.password").getString()

Loader constraint violation when using Dropwizard Histogram metric in Apache Flink

I am running a streaming job on Flink 1.9.1 cluster and trying to get a histogram of values into our Prometheus metric collector. Per recommendation in Flink docs, I used Dropwizard histogram implementation with the Flink-provided wrapper, however when submitting job onto cluster, it crashes with the following traceback:
java.lang.LinkageError: loader constraint violation: when resolving method "org.apache.flink.dropwizard.metrics.DropwizardHistogramWrapper.<init>(Lcom/codahale/metrics/Histogram;)V" the class loader (instance of org/apache/flink/util/ChildFirstClassLoader) of the current class, com/example/foo/metrics/FooMeter, and the class loader (instance of sun/misc/Launcher$AppClassLoader) for the method's defining class, org/apache/flink/dropwizard/metrics/DropwizardHistogramWrapper, have different Class objects for the type com/codahale/metrics/Histogram used in the signature
at com.example.foo.metrics.FooMeter.<init>(FooMeter.scala:11)
at com.example.foo.transform.ValidFoos$.open(ValidFoos.scala:15)
at org.apache.flink.api.common.functions.util.FunctionUtils.openFunction(FunctionUtils.java:36)
at org.apache.flink.streaming.api.operators.AbstractUdfStreamOperator.open(AbstractUdfStreamOperator.java:102)
at org.apache.flink.streaming.api.operators.StreamFlatMap.open(StreamFlatMap.java:43)
at org.apache.flink.streaming.runtime.tasks.StreamTask.openAllOperators(StreamTask.java:532)
at org.apache.flink.streaming.runtime.tasks.StreamTask.invoke(StreamTask.java:396)
at org.apache.flink.runtime.taskmanager.Task.doRun(Task.java:705)
at org.apache.flink.runtime.taskmanager.Task.run(Task.java:530)
at java.lang.Thread.run(Thread.java:748)
I have found similar error in the mailing list, however using shadowJar plugin in Gradle didn't help.
Is there something I am missing?
Relevant code here:
import com.codahale.metrics.{Histogram, SlidingWindowReservoir}
import org.apache.flink.dropwizard.metrics.DropwizardHistogramWrapper
import org.apache.flink.metrics.{MetricGroup, Histogram => FlinkHistogram}
class FooMeter(metricGroup: MetricGroup, name: String) {
private var histogram: FlinkHistogram = metricGroup.histogram(
name, new DropwizardHistogramWrapper(new Histogram(new SlidingWindowReservoir(500))))
def record(fooValue: Long): Unit = {
histogram.update(fooValue)
}
}
object ValidFoos extends RichFlatMapFunction[Try[FooData], Foo] {
#transient private var fooMeter: FooMeter = _
override def open(parameters: Configuration): Unit = {
fooMeter = new FooMeter(getRuntimeContext.getMetricGroup, "foo_values")
}
override def flatMap(value: Try[FooData], out: Collector[FooData]): Unit = {
Transform.validFoo(value) foreach (foo => {
fooMeter.record(foo.value)
out.collect(foo)
})
}
}
build.gradle:
plugins {
id 'scala'
id 'application'
id 'com.github.johnrengelman.shadow' version '2.0.4'
}
ext {
flinkVersion = "1.9.1"
scalaBinaryVersion = "2.11"
scalaVersion = "2.11.12"
}
dependencies {
implementation(
"org.apache.flink:flink-streaming-scala_${scalaBinaryVersion}:${flinkVersion}",
"org.apache.flink:flink-connector-kafka_${scalaBinaryVersion}:${flinkVersion}",
"org.apache.flink:flink-runtime-web_${scalaBinaryVersion}:${flinkVersion}",
"org.apache.flink:flink-json:${flinkVersion}"
"org.apache.flink:flink-metrics-dropwizard:${flinkVersion}",
"org.scala-lang:scala-library:${scalaVersion}",
)
}
shadowJar {
relocate("org.apache.flink.dropwizard", "com.example.foo.shaded.dropwizard")
relocate("com.codahale", "com.example.foo.shaded.codahale")
}
jar {
zip64 = true
archiveName = rootProject.name + '-all.jar'
manifest {
attributes('Main-Class': 'com.example.foo.Foo')
}
from {
configurations.compileClasspath.collect {
it.isDirectory() ? it : zipTree(it)
}
configurations.runtimeClasspath.collect {
it.isDirectory() ? it : zipTree(it)
}
}
}
Further Info:
Running the code locally works
Flink cluster is custom-compiled with following directory structure:
# find /usr/lib/flink/
/usr/lib/flink/
/usr/lib/flink/plugins
/usr/lib/flink/plugins/flink-metrics-influxdb-1.9.1.jar
/usr/lib/flink/plugins/flink-s3-fs-hadoop-1.9.1.jar
/usr/lib/flink/plugins/flink-metrics-graphite-1.9.1.jar
/usr/lib/flink/plugins/flink-metrics-prometheus-1.9.1.jar
/usr/lib/flink/plugins/flink-cep_2.11-1.9.1.jar
/usr/lib/flink/plugins/flink-python_2.11-1.9.1.jar
/usr/lib/flink/plugins/flink-queryable-state-runtime_2.11-1.9.1.jar
/usr/lib/flink/plugins/flink-sql-client_2.11-1.9.1.jar
/usr/lib/flink/plugins/flink-metrics-slf4j-1.9.1.jar
/usr/lib/flink/plugins/flink-state-processor-api_2.11-1.9.1.jar
/usr/lib/flink/plugins/flink-oss-fs-hadoop-1.9.1.jar
/usr/lib/flink/plugins/flink-metrics-statsd-1.9.1.jar
/usr/lib/flink/plugins/flink-swift-fs-hadoop-1.9.1.jar
/usr/lib/flink/plugins/flink-gelly-scala_2.11-1.9.1.jar
/usr/lib/flink/plugins/flink-azure-fs-hadoop-1.9.1.jar
/usr/lib/flink/plugins/flink-metrics-datadog-1.9.1.jar
/usr/lib/flink/plugins/flink-shaded-netty-tcnative-dynamic-2.0.25.Final-7.0.jar
/usr/lib/flink/plugins/flink-s3-fs-presto-1.9.1.jar
/usr/lib/flink/plugins/flink-cep-scala_2.11-1.9.1.jar
/usr/lib/flink/plugins/flink-gelly_2.11-1.9.1.jar
/usr/lib/flink/lib
/usr/lib/flink/lib/flink-metrics-influxdb-1.9.1.jar
/usr/lib/flink/lib/flink-metrics-graphite-1.9.1.jar
/usr/lib/flink/lib/flink-metrics-prometheus-1.9.1.jar
/usr/lib/flink/lib/flink-table_2.11-1.9.1.jar
/usr/lib/flink/lib/flink-metrics-slf4j-1.9.1.jar
/usr/lib/flink/lib/log4j-1.2.17.jar
/usr/lib/flink/lib/slf4j-log4j12-1.7.15.jar
/usr/lib/flink/lib/flink-metrics-statsd-1.9.1.jar
/usr/lib/flink/lib/flink-metrics-datadog-1.9.1.jar
/usr/lib/flink/lib/flink-table-blink_2.11-1.9.1.jar
/usr/lib/flink/lib/flink-dist_2.11-1.9.1.jar
/usr/lib/flink/bin/...

Grails 3.3.0 with postgresql 10.1 as database and spring-security-core gives "object references an unsaved transient instance" error

I have to make a Grails 3.3.0 web interface for my internship with PostgreSQL version 10.1 as database and spring-security-core version 3.2.0.
I've installed PostgreSQL on my Linux laptop and created the webInterfaceDev database with the user Postgres.
However, every time I want to start the project I get the error "object references an unsaved transient instance".
This is the error that I get:
2017-11-23 11:26:55.634 ERROR --- [ main] o.s.boot.SpringApplication : Application startup failed
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.domain.auth.User
at org.hibernate.engine.internal.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:279)
at org.hibernate.type.EntityType.getIdentifier(EntityType.java:462)
at org.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:153)
at org.hibernate.loader.Loader.bindPositionalParameters(Loader.java:2051)
at org.hibernate.loader.Loader.bindParameterValues(Loader.java:2020)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1950)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1903)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1881)
at org.hibernate.loader.Loader.doQuery(Loader.java:925)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:342)
at org.hibernate.loader.Loader.doList(Loader.java:2622)
at org.hibernate.loader.Loader.doList(Loader.java:2605)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2434)
at org.hibernate.loader.Loader.list(Loader.java:2429)
at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:109)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1787)
at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:363)
at org.grails.orm.hibernate.query.AbstractHibernateQuery.listForCriteria(AbstractHibernateQuery.java:716)
at org.grails.orm.hibernate.query.AbstractHibernateQuery.list(AbstractHibernateQuery.java:706)
at org.grails.datastore.gorm.finders.FindAllByFinder.invokeQuery(FindAllByFinder.java:54)
at org.grails.datastore.gorm.finders.FindAllByFinder$1.doInSession(FindAllByFinder.java:48)
at org.grails.datastore.mapping.core.DatastoreUtils.execute(DatastoreUtils.java:319)
at org.grails.datastore.gorm.finders.AbstractFinder.execute(AbstractFinder.java:42)
at org.grails.datastore.gorm.finders.FindAllByFinder.doInvokeInternal(FindAllByFinder.java:45)
at org.grails.datastore.gorm.finders.DynamicFinder.invoke(DynamicFinder.java:254)
at org.grails.datastore.gorm.finders.DynamicFinder.invoke(DynamicFinder.java:392)
at org.grails.datastore.gorm.finders.FinderMethod$invoke$0.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:141)
at org.grails.datastore.gorm.GormStaticApi.methodMissing(GormStaticApi.groovy:185)
at org.grails.datastore.gorm.GormEntity$Trait$Helper.staticMethodMissing(GormEntity.groovy:756)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1446)
at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:899)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:168)
at com.domain.auth.UserRole.staticMethodMissing(UserRole.groovy)
at com.domain.auth.UserRole.$static_methodMissing(UserRole.groovy)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
at groovy.lang.MetaClassImpl.invokeStaticMissingMethod(MetaClassImpl.java:1499)
at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1487)
at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:53)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at com.domain.auth.User.getAuthorities(User.groovy:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
at org.codehaus.groovy.runtime.metaclass.MethodMetaProperty$GetBeanMethodMetaProperty.getProperty(MethodMetaProperty.java:76)
at org.codehaus.groovy.runtime.callsite.GetEffectivePogoPropertySite.getProperty(GetEffectivePogoPropertySite.java:85)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:296)
at web_interface.BootStrap$_closure1.doCall(BootStrap.groovy:9)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1087)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
at groovy.lang.Closure.call(Closure.java:414)
at groovy.lang.Closure.call(Closure.java:408)
at grails.util.Environment.evaluateEnvironmentSpecificBlock(Environment.java:535)
at grails.util.Environment.executeForEnvironment(Environment.java:528)
at grails.util.Environment.executeForCurrentEnvironment(Environment.java:504)
at org.grails.web.servlet.boostrap.DefaultGrailsBootstrapClass.callInit(DefaultGrailsBootstrapClass.java:74)
at org.grails.web.servlet.context.GrailsConfigUtils.executeGrailsBootstraps(GrailsConfigUtils.java:65)
at org.grails.plugins.web.servlet.context.BootStrapClassRunner.onStartup(BootStrapClassRunner.groovy:53)
at grails.boot.config.GrailsApplicationPostProcessor.onApplicationEvent(GrailsApplicationPostProcessor.groovy:261)
at grails.boot.config.GrailsApplicationPostProcessor.onApplicationEvent(GrailsApplicationPostProcessor.groovy)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:167)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:393)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:347)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:883)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.finishRefresh(EmbeddedWebApplicationContext.java:144)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
at grails.boot.GrailsApp.run(GrailsApp.groovy:83)
at grails.boot.GrailsApp.run(GrailsApp.groovy:387)
at grails.boot.GrailsApp.run(GrailsApp.groovy:374)
at grails.boot.GrailsApp$run.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)
at web_interface.Application.main(Application.groovy:8)
FAILURE: Build failed with an exception.
Below is the code that I used:
grails-app/conf/application.yml
---
grails:
profile: web
codegen:
defaultPackage: web_interface
spring:
transactionManagement:
proxies: false
gorm:
reactor:
# Whether to translate GORM events into Reactor events
# Disabled by default for performance reasons
events: false
info:
app:
name: '#info.app.name#'
version: '#info.app.version#'
grailsVersion: '#info.app.grailsVersion#'
spring:
main:
banner-mode: "off"
groovy:
template:
check-template-location: false
# Spring Actuator Endpoints are Disabled by Default
endpoints:
enabled: false
jmx:
enabled: true
---
grails:
mime:
disable:
accept:
header:
userAgents:
- Gecko
- WebKit
- Presto
- Trident
types:
all: '*/*'
atom: application/atom+xml
css: text/css
csv: text/csv
form: application/x-www-form-urlencoded
html:
- text/html
- application/xhtml+xml
js: text/javascript
json:
- application/json
- text/json
multipartForm: multipart/form-data
pdf: application/pdf
rss: application/rss+xml
text: text/plain
hal:
- application/hal+json
- application/hal+xml
xml:
- text/xml
- application/xml
urlmapping:
cache:
maxsize: 1000
controllers:
defaultScope: singleton
converters:
encoding: UTF-8
views:
default:
codec: html
gsp:
encoding: UTF-8
htmlcodec: xml
codecs:
expression: html
scriptlets: html
taglib: none
staticparts: none
endpoints:
jmx:
unique-names: true
---
hibernate:
cache:
queries: false
use_second_level_cache: false
use_query_cache: false
dataSource:
pooled: true
jmxExport: true
#mem database driver and password
#driverClassName: org.h2.Driver
#username: sa
#password:
#PostgreSQL driver and password
driverClassName: org.postgresql.Driver
username: postgres
password: password
environments:
development:
dataSource:
dbCreate: update #use create-drop or update
#Use for mem database
#url: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
#Use for PostgreSQL database
url: jdbc:postgresql://localhost:5432/webInterfaceDev
test:
dataSource:
dbCreate: update
url: jdbc:postgresql:webInterfaceDev
production:
dataSource:
dbCreate: update
url: jdbc:postgresql:webInterfaceDev
properties:
jmxEnabled: true
initialSize: 5
maxActive: 50
minIdle: 5
maxIdle: 25
maxWait: 10000
maxAge: 600000
timeBetweenEvictionRunsMillis: 5000
minEvictableIdleTimeMillis: 60000
validationQuery: SELECT 1
validationQueryTimeout: 3
validationInterval: 15000
testOnBorrow: true
testWhileIdle: true
testOnReturn: false
jdbcInterceptors: ConnectionState
defaultTransactionIsolation: 2 # TRANSACTION_READ_COMMITTED
Below is the build.gradle code:
buildscript {
repositories {
mavenLocal()
maven { url "https://repo.grails.org/grails/core" }
}
dependencies {
classpath "org.grails:grails-gradle-plugin:$grailsVersion"
classpath "org.grails.plugins:hibernate5:${gormVersion-".RELEASE"}"
classpath "com.bertramlabs.plugins:asset-pipeline-gradle:2.14.2"
}
}
version "0.1"
group "web_interface"
apply plugin:"eclipse"
apply plugin:"idea"
apply plugin:"war"
apply plugin:"org.grails.grails-web"
apply plugin:"asset-pipeline"
apply plugin:"org.grails.grails-gsp"
repositories {
mavenLocal()
maven { url "https://repo.grails.org/grails/core" }
}
dependencies {
//plugins needed to make the user system
compile 'org.grails.plugins:spring-security-core:3.2.0'
compile 'org.grails.plugins:spring-security-ui:3.1.1'
//end of the plugins needed
//postgresql
compile 'org.postgresql:postgresql:42.1.4.jre7'
//end
compile "org.springframework.boot:spring-boot-starter-logging"
compile "org.springframework.boot:spring-boot-autoconfigure"
compile "org.grails:grails-core"
compile "org.springframework.boot:spring-boot-starter-actuator"
compile "org.springframework.boot:spring-boot-starter-tomcat"
compile "org.grails:grails-web-boot"
compile "org.grails:grails-logging"
compile "org.grails:grails-plugin-rest"
compile "org.grails:grails-plugin-databinding"
compile "org.grails:grails-plugin-i18n"
compile "org.grails:grails-plugin-services"
compile "org.grails:grails-plugin-url-mappings"
compile "org.grails:grails-plugin-interceptors"
compile "org.grails.plugins:cache"
compile "org.grails.plugins:async"
compile "org.grails.plugins:scaffolding"
compile "org.grails.plugins:events"
compile "org.grails.plugins:hibernate5"
compile "org.hibernate:hibernate-core:5.1.5.Final"
compile "org.grails.plugins:gsp"
console "org.grails:grails-console"
profile "org.grails.profiles:web"
runtime "org.glassfish.web:el-impl:2.1.2-b03"
runtime "com.h2database:h2"
runtime "org.apache.tomcat:tomcat-jdbc"
runtime "com.bertramlabs.plugins:asset-pipeline-grails:2.14.2"
testCompile "org.grails:grails-gorm-testing-support"
testCompile "org.grails.plugins:geb"
testCompile "org.grails:grails-web-testing-support"
testRuntime "org.seleniumhq.selenium:selenium-htmlunit-driver:2.47.1"
testRuntime "net.sourceforge.htmlunit:htmlunit:2.18"
}
bootRun {
jvmArgs('-Dspring.output.ansi.enabled=always')
addResources = true
}
assets {
minifyJs = true
minifyCss = true
}
Below is the User.groovy code:
package com.domain.auth
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import grails.compiler.GrailsCompileStatic
#GrailsCompileStatic
#EqualsAndHashCode(includes='username')
#ToString(includes='username', includeNames=true, includePackage=false)
class User implements Serializable {
private static final long serialVersionUID = 1
String username
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
Set<Role> getAuthorities() {
(UserRole.findAllByUser(this) as List<UserRole>)*.role as Set<Role>
}
static constraints = {
password nullable: false, blank: false, password: true
username nullable: false, blank: false, unique: true
}
static mapping = {
table '`User`' //user is properity for postgresql insted i use now User as table name
password column: '`password`'
}
}
Bootstrap.groovy code:
package web_interface
import com.domain.auth.*
//class BootStrap {
// def passwordEncoder
//
// def init = { servletContext ->
// def adminRole = Role.findOrSaveWhere(authority:"ROLE_ADMIN")
// def user = User.findOrSaveWhere(username:"admin", password: "password").save(flush: true)
// if(!user.authorities.contains(adminRole)){
// UserRole.create(user,adminRole,true)
// }
// }
// def destroy = {
// }
//}
class BootStrap{
def init = { servletContext ->
if(User.count() == 0){
def adminRole = new Role(authority: 'ROLE_ADMIN').save(flush:true)
def admin = new User(username: 'admin', password: 'password').save(flush:true)
UserRole.create admin, adminRole
// as we call to create, flush the session explicitly ..
UserRole.withSession {
it.flush()
it.clear()
}
// instead you can put >
// new UserRole(admin, adminRole).save(flush:true)
// Do more stuff with admin user
}
}
def destroy = {
}
}
UserRole.groovy code:
package com.domain.auth
import grails.gorm.DetachedCriteria
import groovy.transform.ToString
import org.codehaus.groovy.util.HashCodeHelper
import grails.compiler.GrailsCompileStatic
#GrailsCompileStatic
#ToString(cache=true, includeNames=true, includePackage=false)
class UserRole implements Serializable {
private static final long serialVersionUID = 1
User user
Role role
#Override
boolean equals(other) {
if (other instanceof UserRole) {
other.userId == user?.id && other.roleId == role?.id
}
}
#Override
int hashCode() {
int hashCode = HashCodeHelper.initHash()
if (user) {
hashCode = HashCodeHelper.updateHash(hashCode, user.id)
}
if (role) {
hashCode = HashCodeHelper.updateHash(hashCode, role.id)
}
hashCode
}
static UserRole get(long userId, long roleId) {
criteriaFor(userId, roleId).get()
}
static boolean exists(long userId, long roleId) {
criteriaFor(userId, roleId).count()
}
private static DetachedCriteria criteriaFor(long userId, long roleId) {
UserRole.where {
user == User.load(userId) &&
role == Role.load(roleId)
}
}
static UserRole create(User user, Role role, boolean flush = false) {
def instance = new UserRole(user: user, role: role)
instance.save(flush: flush)
instance
}
static boolean remove(User u, Role r) {
if (u != null && r != null) {
UserRole.where { user == u && role == r }.deleteAll()
}
}
static int removeAll(User u) {
u == null ? 0 : UserRole.where { user == u }.deleteAll() as int
}
static int removeAll(Role r) {
r == null ? 0 : UserRole.where { role == r }.deleteAll() as int
}
static constraints = {
user nullable: false, unique: true
role nullable: false, validator: { Role r, UserRole ur ->
if (ur.user?.id) {
if (UserRole.exists(ur.user.id, r.id)) {
return ['userRole.exists']
}
}
user.save()
}
}
static mapping = {
id composite: ['user', 'role']
version false
}
}
Role.groovy code:
package com.domain.auth
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import grails.compiler.GrailsCompileStatic
#GrailsCompileStatic
#EqualsAndHashCode(includes='authority')
#ToString(includes='authority', includeNames=true, includePackage=false)
class Role implements Serializable {
private static final long serialVersionUID = 1
String authority
static constraints = {
authority nullable: false, blank: false, unique: true
}
static mapping = {
cache true
}
}
Long story in short
Your User.findOrSaveWhere(username:"admin", password:"password") is the problem. If you try without password:"password" your code will run considering setting the password user.password='password' while initiating new User.
The saved password in the DB is hashed and it doesn't match with your given password. So, everytime you run the app, it doesn't find matching user and tries to save a new User with same username violating the unique constraints.
Deatils -
I tried with below codes -
def xadminRole = Role.findOrSaveWhere(authority:"XYZROLE_XADMIN")
def xuser = User.findOrSaveWhere(username:"xxzadmin", password:"password")
if(!xuser.authorities.contains(xadminRole)){
UserRole.create(xuser,xadminRole,true)
}
First time its working fine and inserting the User
2nd time I ran the app i got user instance has below errors
Field error in object 'com.xxx.ovr.User' on field 'username': rejected value [xxzadmin]; codes [[username,class com.xxx.ovr.User,xxzadmin]; default message [Property [{0}] of class [{1}] with value [{2}] must be unique]
and finally
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.xxx.ovr.User
The user's password-
$2a$10$b1Ybjt9.XVgkDi.HRgGgpeyL7WsSFMFl0jpSWy60JfTfTDNRQH/Fu
$2a$10$8HTYeE8uJgmMzclc0lku5euUpNfqa3RUZeBBs7XaJ9Z5CpT/0Prtq
So you can not find a user with plain password - 'password' which is saved in DB after hashed (example given above). To match a user with username and password you can check the posts -
spring security encode password with bcrypt algorithm
Grails Spring-Security -how to compare passwords-
UPDATE
With #BurtBeckwith's useful comment, I corrected the answer putting "hashed" in place of "encrypted"
For Password Hash algorithm, please check 1.2 and 3.3.2 section of
https://grails-plugins.github.io/grails-spring-security-core/latest/
Related post
Using BCrypt password hashing with Spring Security Grails plugin
For difference between Hash and Encryption please check
Difference between Hashing a Password and Encrypting it
Fundamental difference between Hashing and Encryption algorithms
In your Bootstrap.groovy, try simple thing as below
def init = { servletContext ->
if(User.count() == 0){
def adminRole = new Role(authority: 'ROLE_ADMIN').save(flush:true)
def admin = new User(username: 'admin', password: 'testpassed').save(flush:true)
UserRole.create admin, adminRole
// as we call to create, flush the session explicitly ..
UserRole.withSession {
it.flush()
it.clear()
}
// instead you can put >
// new UserRole(admin, adminRole).save(flush:true)
// Do more stuff with admin user
}
}
Just a small thing, put your db url in your application.yml
url: jdbc:postgresql://localhost:5432/yourDBName

java.lang.RuntimeException: Unexpected global [result]

I have this class, that reads rule files, insert facts and run rules.
public class RuleRunner {
private KieServices kieServices = KieServices.Factory.get();
public enum RuleType {
XLS,
DRL;
}
private void prepareSession(String ruleResource, RuleType type) {
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
Resource resource = kieServices.getResources().newClassPathResource(ruleResource);
switch(type) {
case XLS: {
resource.setResourceType(ResourceType.DTABLE);
break;
}
case DRL: {
resource.setResourceType(ResourceType.DRL);
break;
}
}
kieFileSystem.write(resource);
KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem);
kieBuilder.buildAll();
if (hasErrors(kieBuilder)) {
System.out.println("Failed to build!");
return;
}
}
private boolean hasErrors(KieBuilder builder) {
if (builder.getResults().getMessages().size() > 0) {
return true;
}
return false;
}
public void runRules(Object[] facts, GlobalVariable[] variables, String ruleResource, RuleType type) {
prepareSession(ruleResource, type);
KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());
KieSession kieSession = kieContainer.newKieSession();
for (GlobalVariable variable: variables) {
kieSession.setGlobal(variable.getVariableName(), variable);
}
for(Object fact: facts) {
kieSession.insert(fact);
}
kieSession.fireAllRules();
kieSession.dispose();
}
}
And I have this rule
package com.pack.drools.apps;
import com.pack.drools.apps.domain.Person;
import com.pack.drools.apps.domain.GlobalVariable;
global GlobalVariable result
rule "if person has less that 10 cash then hes poor"
when
$person:Person(cash < 10)
then
result.setResult(-1);
end
rule "if person has more than 90 cash then hes rich"
when
$person:Person(cash > 90)
then
result.setResult(-2);
end
rule "if person has more than 10 and less than 90 then hes average"
when
$person:Person(cash >= 10 && cash <= 90)
then
result.setResult(-3);
end
However when I try to run my application
package pack.rup.drools.apps;
import pack.rup.drools.apps.core.RuleRunner;
import pack.rup.drools.apps.core.RuleRunner.RuleType;
import pack.rup.drools.apps.domain.GlobalVariable;
import pack.rup.drools.apps.domain.Person;
public class Main {
private static final String DEFAULT_PACKAGE = "pack/rup/drools/apps/";
private static final String XLS_FILE = DEFAULT_PACKAGE + "rule.xls";
private static final String DRL_FILE = DEFAULT_PACKAGE + "rule.drl";
public static void main(String[] args) {
RuleRunner ruleRunner = new RuleRunner();
// build fact
Person person = new Person();
person.setName("John");
person.setCash(100);
GlobalVariable result = new GlobalVariable();
result.setVariableName("result");
// ruleRunner.runRules(new Object[] { person }, new GlobalVariable[] { result }, XLS_FILE, RuleType.XLS);
ruleRunner.runRules(new Object[] { person }, new GlobalVariable[] { result }, DRL_FILE, RuleType.DRL);
System.out.println("Rule result: " + result.getResult());
}
}
my log looks like this
10:13:00.974 [main] INFO o.d.c.k.b.impl.KieRepositoryImpl - KieModule was added: MemoryKieModule[releaseId=org.default:arti
fact:1.0.0-SNAPSHOT]
10:13:00.982 [main] INFO o.d.c.k.b.impl.ClasspathKieProject - Found kmodule: file:/D:/workTestProjects/simpleDroolsApps/sda
-core/build/resources/main/META-INF/kmodule.xml
10:13:00.982 [main] DEBUG o.d.c.k.b.impl.ClasspathKieProject - KieModule URL type=file url=/D:/workTestProjects/simpleDrools
Apps/sda-core/build/resources/main
10:13:01.026 [main] WARN o.d.c.k.b.impl.ClasspathKieProject - Unable to find pom.properties in /D:/workTestProjects/simpleD
roolsApps/sda-core/build/resources/main
10:13:01.027 [main] WARN o.d.c.k.b.impl.ClasspathKieProject - As folder project tried to fall back to pom.xml, but could no
t find one for null
10:13:01.027 [main] WARN o.d.c.k.b.impl.ClasspathKieProject - Unable to load pom.properties from/D:/workTestProjects/simple
DroolsApps/sda-core/build/resources/main
10:13:01.027 [main] WARN o.d.c.k.b.impl.ClasspathKieProject - Cannot find maven pom properties for this project. Using the
container's default ReleaseId
10:13:01.027 [main] DEBUG o.d.c.k.b.impl.ClasspathKieProject - Discovered classpath module org.default:artifact:1.0.0-SNAPSH
OT
10:13:01.028 [main] INFO o.d.c.k.b.impl.KieRepositoryImpl - KieModule was added: FileKieModule[releaseId=org.default:artifa
ct:1.0.0-SNAPSHOT,file=D:\workTestProjects\simpleDroolsApps\sda-core\build\resources\main]
10:13:01.035 [main] WARN o.d.c.k.b.impl.AbstractKieModule - No files found for KieBase defaultKieBase, searching folder D:\
workTestProjects\simpleDroolsApps\sda-core\build\resources\main
10:13:01.131 [main] DEBUG o.drools.core.impl.KnowledgeBaseImpl - Starting Engine in PHREAK mode
Exception in thread "main" java.lang.RuntimeException: Unexpected global [result]
at org.drools.core.impl.StatefulKnowledgeSessionImpl.setGlobal(StatefulKnowledgeSessionImpl.java:1163)
at pack.rup.drools.apps.core.RuleRunner.runRules(RuleRunner.java:57)
at pack.rup.drools.apps.Main.main(Main.java:27)
:sda-core:run FAILED
It seems that you must use a particular directory when writing DRL or XLS resources to the KieFileSystem. Try
String filename = ...; // code that set filename to (e.g.) rule.drl
kieFileSystem.write( "src/main/resources/" + filename, resource );
Also, in your DRL you have
import com.pack.drools.apps.domain....
whereas in Main.java there is
import pack.rup.drools.apps.domain....
These imports should be from the same package.
Edit To test what globals are in the session:
Globals globals = kieSession.getGlobals();
System.out.println( globals.getGlobalKeys() );
We spent 2 days with my colleague and finally figured out that "Unexpected global" error happens when your DRL is empty because of compilation errors, that's why addGlobal() can't find any global declaration.
Once DRL compiler does not throw any exception on errors, instead you can check it yourself using:
if (kieBuilder.hasErrors()) {
System.out.print( kieBuilder.getErrors() );
}
If you insert a global, you must consume it. For example, if you have:
ArrayList<Thing> myThings = new ArrayList<Thing>();
kSession.setGlobal("myThings", myThings);
In your DRL files, you must have at least one matching:
global ArrayList<Thing> myThings;
Otherwise, you get:
java.lang.RuntimeException: Unexpected global [myThings]
at org.drools.core.impl.StatefulKnowledgeSessionImpl.setGlobal(StatefulKnowledgeSessionImpl.java:1200)
at com.sample.ThingTest.test(ThingTest.java:37)

When does Play load application.conf?

Is application.conf already loaded when the code in Global.scala is executed? I'm asking because I've tried to read some configuration items from Global.scala and I always get None. Is there any workaround?
In Java it's available beforeStart(Application app) already
public class Global extends GlobalSettings {
public void beforeStart(Application app) {
String secret = Play.application().configuration().getString("application.secret");
play.Logger.debug("Before start secret is: " + secret);
super.beforeStart(app);
}
}
As it's required to i.e. configuring DB connection, most probably Scala works the same way (can't check)
Here below is how to read the configuration just after it has been loaded but before the application actually starts:
import play.api.{Configuration, Mode}
import play.api.GlobalSettings
import java.io.File
import utils.apidocs.InfoHelper
object Global extends GlobalSettings {
override def onLoadConfig(
config: Configuration,
path: File, classloader:
ClassLoader,
mode: Mode.Mode): Configuration = {
InfoHelper.loadApiInfo(config)
config
}
}
And here below, just for your info, is the source of InfoHelper.loadApiInfo – it just loads API info for Swagger UI:
package utils.apidocs
import play.api.Configuration
import com.wordnik.swagger.config._
import com.wordnik.swagger.model._
object InfoHelper {
def loadApiInfo(config: Configuration) = {
config.getString("application.name").map { appName =>
config.getString("application.domain").map { appDomain =>
config.getString("application.emails.apiteam").map { contact =>
val apiInfo = ApiInfo(
title = s"$appName API",
description = s"""
Fantastic application that makes you smile. You can find our
more about $appName at $appDomain.
""",
termsOfServiceUrl = s"//$appDomain/terms",
contact = contact,
license = s"$appName Subscription and Services Agreement",
licenseUrl = s"//$appDomain/license"
)
ConfigFactory.config.info = Some(apiInfo)
}}}
}
}
I hope it helps.