====== Gradle에서 JPA 2 MetaModel 생성 ====== [[https://github.com/hibernate/hibernate-metamodelgen|Hibernate MetamodelGen]]을 이용하여 JPA2 MetaModel을 생성하는 예를 보여준다. 실제로는 compile 태스크에 들어가는게 좋으나, 현재 지원을 안 해서, 독릭적으로 JavaCompile 태스크를 만들고, 거기서 Annotation Processor만 호출하도록 변경한 것이다. * ''-proc:only'' 옵션 때문에 실제 컴파일을 하지 않는다. * **Java 6** 이상에서만 작동한다. * TODO [[http://netframework.tistory.com/462|Programming is Fun :: Gradle 5.0에서의 querydsl Q-class 생성]] ===== QueryDSL ===== * [[http://honeymon.io/tech/2020/07/09/gradle-annotation-processor-with-querydsl.html|[gradle] 그레이들 Annotation processor 와 Querydsl]] * [[java:querydsl|QueryDSL]]의 경우 [[https://github.com/ewerk/gradle-plugins/tree/master/querydsl-plugin|Graldle QueryDSL Plugin]]으로 해결 가능하다. : [[:intellij_idea|IntelliJ IDEA]] 연동에 문제 일으킴. ''annotationProcessor'' 더 권장. apply plugin: "com.ewerk.gradle.plugins.querydsl" compile "com.querydsl:querydsl-jpa:$queryDslVersion" ext { querydslSrcDir = 'src/main/generated' } querydsl { library = "com.querydsl:querydsl-apt" jpa = true querydslSourcesDir = querydslSrcDir } sourceSets { main { java { srcDirs += file(querydslSrcDir) } } } idea { module { generatedSourceDirs += file(querydslSrcDir) } } * ''compileQueryDsl'' task로 코드 생성을 할 수 있다. gradlew clean cleanQuerydslSourcesDir compileQueryDsl 혹은 gradlew cleanQuerydslSourcesDir initQuerydslSourcesDir compileQuerydsl processQUerydslResources # cleanQuerydslSourcesDir 를 하지 않을 경우 기존 생성된 코드 때문에 오류가 발생함. ===== Cannot find symbol 오류 ===== * [[java:querydsl|QueryDSL]]과 Hibernate/Eclipse Metamodel Generator를 함께 사용할 때 아직 생성되지 않은 메타 모델 클래스를 사용하는 코드들 때문에 ''cannot find symbol'' 에러가 발생할 수 있는데, 이는 이 둘을 서로 따로 생성했을 때 발생하는 현상이다. * 정황상 [[java:lombok|Lombok]]을 함께 사용할 경우 각 AP가 실행된 뒤에 다시 lombok AP가 돌면서 발생하는 것으로 보인다. * 이 둘을 함께 지정해서 APT 를 수행해야 에러가 나지 않는다. "-processor", "com.mysema.query.apt.jpa.JPAAnnotationProcessor,org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor" ===== Gradle Annotation Process 예 ===== http://alvinalexander.com/java/jwarehouse/hibernate/build.gradle.shtml 에 있는 것을 옮겼다. Gradle 기반으로 정적 분석 도구 사용시에 여기서 자동 생성된 클래스는 정적 분석에서 예외처리해줘야 한다.(''/Q[A-Z].*\.class/'', ''/.*\_.class/'') [[java:static_analysis|Java Static Analysis]] 를 참조한다. ext.jpaMetamodelGeneratedDir = "$buildDir/생성된 메타 모델 클래스를 저장할 디렉토리" configurations { jpaMetamodelGen { extendsFrom compile } } dependencies { jpaMetamodelGen "org.hibernate:hibernate-jpamodelgen:1.2.0.Final" } sourceSets { main { java { srcDir jpaMetamodelGeneratedDir } } } idea { module { sourceDirs += file(jpaMetamodelGeneratedDir) } } task generateJpaMetamodel(type: JavaCompile) { def targetDir = file(jpaMetamodelGeneratedDir) def compiledDestinationDir = "${buildDir}/tmp/apt-jpa" doFirst { // 항상 대상 디렉토리를 먼저 비우고 시작해야 한다. delete(targetDir) targetDir.mkdirs() } doLast { delete(compiledDestinationDir) // UP-TO-DATE 방지 } // -proc:only 는 Annotation Processor로 소스 생성만 한다 컴파일은 하지 않음 // -s 경로 는 생성된 소스가 들어갈 디렉토리를 뜻한다. classpath = configurations.jpaMetamodelGen source = sourceSets.main.java destinationDir = file(compiledDestinationDir) options.define( compilerArgs: [ "-nowarn", "-proc:only", "-encoding", "UTF-8", "-s", targetDir.absolutePath, // processor 지정은 안해도 된다. 안하면 모든 어노테이션 프로세서 실행 "-processor", "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor" ] ) } // 필요하면 compileJava가 generateJpaMetamodel 에 의존하도록 변경한다. ==== Lombok 사용시 ==== [[java:lombok|Lombok]] 사용시 문제가 된다면 [[https://medium.com/@geminikim/%EA%B0%9C%EC%9D%B8%EC%B7%A8%ED%96%A5-jpa-%EC%82%AC%EC%9A%A9%EA%B8%B0-querydsl-gradle-lombok-76c509aec60e|개인취향 JPA 사용기 - QueryDSL + Gradle + Lombok – Gemini Kim – Medium]] 참고. [[https://github.com/ewerk/gradle-plugins/issues/59|querydsl + lombok problem · Issue #59 · ewerk/gradle-plugins]] task generateQueryDSL(type: JavaCompile, group: 'build') { source = sourceSets.main.java classpath = configurations.compile destinationDir = queryDslOutput options.compilerArgs = [ "-proc:only", /********************* 핵심 포인트! *********************/ "-processor", 'com.querydsl.apt.jpa.JPAAnnotationProcessor,lombok.launch.AnnotationProcessorHider$AnnotationProcessor' ] } compileJava.dependsOn(generateQueryDSL)