So I'm trying to get the Hibernate Validator Annotation Processor working in a Kotlin project, to check my JSR 380 annotations, with not much luck.
Unfortunately the documentation does not mention how to set it up with Gradle, and obviously with Kotlin we have to use "Kapt" to enable java annotation processors.
Hibernate Validator Annotation Processor Documentation: http://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#validator-annotation-processor
Kapt Documentation: https://kotlinlang.org/docs/reference/kapt.html
I currently have the following config in my build.gradle file relating to the processor:
plugins {
id "org.jetbrains.kotlin.kapt" version "1.3.11"
...
}
apply plugin: 'org.jetbrains.kotlin.kapt'
...
dependencies {
implementation 'org.hibernate:hibernate-validator:6.0.14.Final'
implementation 'org.glassfish:javax.el:3.0.1-b09'
kapt 'org.hibernate:hibernate-validator-annotation-processor:6.0.14.Final'
...
}
kapt {
arguments {
arg('methodConstraintsSupported', 'false')
arg('verbose', 'true')
}
}
However whenever I build, I cannot see any output relating to the validator annotation processor and I do not get any build errors when deliberately applying an incorrect annotation (e.g. applying a #Min() annotation to a String field.
If someone could advise on how to get the processor working I would be eternally grateful! :)
I got this working in my build.gradle.kts like so (I'm using Kotlin Script as opposed to Groovy):
plugins {
...
id("org.jetbrains.kotlin.kapt") version "1.3.72"
...
}
dependencies {
...
kapt(
group = "org.hibernate.validator",
name = "hibernate-validator-annotation-processor",
version = "6.0.2.Final"
)
...
}
This correctly gave me errors when building, but only when I applied the validation annotation to the getter. When I was mistakenly applying it to just the constructor argument the validation did not work, and I saw no errors from the annotation processor. For example:
class Thing(
#get:AssertTrue
var name: String
)
Related
I am having below class
class TestClientSpec extends Specification {
TestClient testClient
RestTemplate restTemplate
def setup() {
restTemplate = Mock()
testClient = new TestClient(restTemplate)
}
def 'successful'() {
given:
def url = 'https://test123'
when:
testClient.getValue(url)
then:
1 * restTemplate.getForEntity(url, Test.class)
}
}
when I try to run this test got below error
Cannot create mock for class org.springframework.web.client.RestTemplate. Mocking of non-interface types requires a code generation library. Please put an up-to-date version of byte-buddy or cglib-nodep on the class path.
org.spockframework.mock.CannotCreateMockException: Cannot create mock for class org.springframework.web.client.RestTemplate. Mocking of non-interface types requires a code generation library. Please put an up-to-date version of byte-buddy or cglib-nodep on the class path.
After that I have added cglib dependnecy and it's working fine
implementation group: 'cglib', name: 'cglib-nodep', version: '3.3.0'
But not sure why it's throws the above error and how cglib fixing this?
Spock uses a bytecode generator lib, either cglib or byte-buddy, to generate classes at runtime in order to be able to mock classes.
The dependencies on these libs are optional, so that you can choose whether to use them or not, as you might as well use some dedicated mock libraries for all your mocking needs (e.g. PowerMock).
How adding a bytecode lib to the classpath can fix this?
Well, by enabling the necessary code in Spock... in case of Cglib, CglibMockFactory.
Spock seems to find out which lib is available to use for mocking at MockInstantiator... if you know Java reflection, doing that kind of thing is not hard, just do something like Class.forName("org.objenesis.Objenesis") and if that doesn't throw ClassNotFoundException you can use that.
I use gRPC framework with Proto 3. We have a java code coverage tool Jacoco which scans java byte code for java "annotation" #Generated in compiled classes and if it has one, it skips that java class from coverage. But Proto-compiler adds this annotation:
#javax.annotation.Generated(
value = "by gRPC proto compiler (version 1.20.0)",
comments = "Source: myProto.proto")
public class MyClass {
...
}
But the annotation javax.annotation.Generated has #Retention(value=SOURCE) which doesn't exist in compiled classes.
Is there a way to add annotation to java generated files from protobuf as compile-time?
That's an old question, but still
https://github.com/protocolbuffers/protobuf/issues/42
So you suppose to add --java_out=annotate_code to the list of protoc options.
If you use https://github.com/google/protobuf-gradle-plugin gradle plugin for code generation, then you can do like this(Gradle Kotlin DSL):
protobuf {
generateProtoTasks {
all().forEach { task ->
task.builtins {
getByName("java") {
option("annotate_code")
}
}
}
}
}
I have a Kotlin Gradle project. I added Lombok as a dependency and also registered it with kapt
compileOnly("org.projectlombok:lombok:$lombokVersion")
kapt("org.projectlombok:lombok:$lombokVersion")
I would like to use the #Slf4j annotation for automatic logger generation. It works for Java classes but not for the Kotlin ones.
Is using Kotlin and Lombok together even possible as of now? If I annotate a Kotlin class with #Slf4j and use log inside it I get
Unresolved reference: log
Evidently no annotation processing is applied.
Lombok does not run on your source code, but on the AST. Anyway, it is an annotation processor that is run at compile-time by the Java compiler. The Kotlin compiler does not use these annotation processors. See also the answer https://stackoverflow.com/a/35530223/2621917 straight from the horse’s mouth.
You cannot use annotation #Slf4j, but manually create its object in the class required.
Refer https://www.reddit.com/r/Kotlin/comments/8gbiul/slf4j_loggers_in_3_ways/
If all you want to use Lombok for is #Slf4j, then I'd suggest using kotlin-logging instead: https://github.com/MicroUtils/kotlin-logging
It's a simple wrapper around slf4j, so instead of annotating your class with #Slf4j, you use:
// Place definition above class declaration to make field static
private val logger = KotlinLogging.logger {}
// ...
logger.debug { "A message only logged if debug is enabled. With $variable support." }
Lombok's builder annotation support has been added to kotlin 1.8 as of late December 2022.
You can learn how to configure the plugin here.
In Short, add
plugins {
id 'org.jetbrains.kotlin.plugin.lombok' version '1.8.0'
id 'io.freefair.lombok' version '5.3.0'
}
to your Groovy/Gradle files, and/or take a look at the sample project.
It's not supported and, by the looks of things, it isn't going to be.
from kotlin 1.7.20 with K2 compiler it is possible.
https://kotlinlang.org/docs/whatsnew1720.html#support-for-kotlin-k2-compiler-plugins
For logging the best I could do - because #Slf4j did not work - was like creating abstract log class like:
package org.example
import org.slf4j.LoggerFactory
import org.slf4j.Logger
abstract class Log {
val log: Logger = LoggerFactory.getLogger(this.javaClass)
}
and usage:
package org.example
class MyClass {
companion object : Log() {}
#Test
fun someFun() {
log.info("Logging info")
}
}
I can't see how it would work without additional support from the lombok team.
Lombok is based on annotation processing so it runs during compilation time and runs on your source code, so I guess it assumes Java's syntax.
I use kotlin and java with spring boot to develop my project.
My build tool is gradle, a task is defined as follows:
configurations {
providedRuntime
jpametamodel
}
dependencies {
jpametamodel ('org.hibernate:hibernate-jpamodelgen:4.3.11.Final')
}
task generateMetaModel(type: JavaCompile, group: 'build', description: 'metamodel generate') {
source = sourceSets.main.java
classpath = configurations.compile + configurations.jpametamodel
options.compilerArgs = ["-proc:only"]
destinationDir = sourceSets.generated.java.srcDirs.iterator().next()
doFirst {
delete(sourceSets.generated.java.srcDirs)
}
}
This task works with out kotlin class, but if I add kotlin class, the task cannot work by throw the following errors:
Hibernate JPA 2 Static-Metamodel Generator 4.3.11.Final
/.../src/main/java/com/app/web/rest/UserResource.java:18:
Cannot find .....
import com.app.web.rest.dto.SimpleUser;
^
Symbol: Class SimpleUser
Position: Package com.app.web.rest.dto
The SimpleUser is defined in kotlin file:
SimpleUser.kt
data class SimpleUser(val str:String)
The Hibernate meta-model generator is implemented as a JSR 269 annotation processor. When using Kotlin, you'll need to enable annotation processing explicitly by applying the kapt compiler plugin. When you do that, you'll find that the meta-model gets generated for Kotlin entities.
I have a project depending on Netflix Feign and Glassfish Jersey implementation.
Feign uses the 1.1 spec of JAX-RS (JSR 311), and glassfish jersey implementation uses the 2.0 spec. The 2.0 is backward compatible, but the Gradle dependency name is changed.
Thus I have two dependencies in my project:
javax.ws.rs:jsr311-api:1.1.1
javax.ws.rs:javax-ws-rs-api:2.0.1
Both implements the same classes in the same packages, but one according to 1.x and one according to 2.x
In my Java code, I can only point out the class name and the package.
Can I tell Gradle that this actually is the same package although the name differs and in that way only get one set of the implementing classes in the class path?
Right now it is random what version of the classes that the JVM and Compiler picks. Sometime it does not compile, sometimes it compiles but does not run (MethodNotFoundException).
In the end, I added this to my gradle file and it looks alright:
configurations.all {
resolutionStrategy.dependencySubstitution {
substitute module('javax.ws.rs:jsr311-api') with module('javax.ws.rs:javax.ws.rs-api:2.0.1')
}
}
The dependency tree no longer includes the javax.ws.rs:jsr311-api dependency, and no more MethodNotFound-exception for javax.ws.rs.core.Application.getProperties(...) method.
I'm not sure that this is the best way, but it works:
configurations.all {
resolutionStrategy.dependencySubstitution {
all { DependencySubstitution d ->
if (d.requested instanceof ModuleComponentSelector && d.requested.name == 'jsr311-api') {
d.useTarget group: d.requested.group, name: 'javax-ws-rs-api', version: d.requested.version
}
}
}
}
Updated:
It's possible to do so another way using nebula.resolution-rules plugin and such configuration:
replace-jsr.json
{
"replace" : [
{
"module" : "javax.ws.rs:jsr311-api",
"with" : "javax.ws.rs:javax-ws-rs-api",
"reason" : "The JSR spec jar maven coordinates changed for 2.0 and later",
"author" : "Andreas Lundgren",
"date" : "2016-08-08T00:00:00.000Z"
}
],
"align": [],
"substitute": [],
"deny": [],
"reject": []
}