Encountered an error while creating a custom repository with Querydsl.(javax.persistence.NoResultException)

48 Views Asked by At

I believe I have correctly set up the dependencies for my Spring Boot version 3.1.8 as shown in the build.gradle code below.

I am trying to implement a feature where I send a unique list of hashtags from articles to the user.

To achieve this, I customized the repository using Querydsl to fetch this data from the Article table

I have also added this functionality to the service and controller layers. I used Thymeleaf to send this data to the user and have also written HTML.

Although all my tests pass, the functionality doesn't work in the actual application. Can someone please assist me in finding a solution?

  • I confirmed that all repository had "final" specified, but the issue persists.

  • Other Querydsl queries (e.g., findByContentContaining) are functioning well.

  • I also tried changing the build and run settings.

    • [ build and run : Intellij, Run and unsing : Gradle ]

    • [ build and run : Intellij, Run and unsing : Intellij ]

    • [ build and run : Gradle , Run and unsing : Gradle ]

< build.gradle >

dependencies {

    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    // JSON API
    implementation 'org.springframework.boot:spring-boot-starter-data-rest' 
    implementation 'org.springframework.data:spring-data-rest-hal-explorer' 
    // server side
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    // Auth
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
    // DB
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    runtimeOnly 'com.h2database:h2'
    runtimeOnly 'com.mysql:mysql-connector-j'
    // queryDSL setting
    implementation "com.querydsl:querydsl-jpa:5.0.0"
    implementation "com.querydsl:querydsl-core:5.0.0"
    implementation "com.querydsl:querydsl-collections:5.0.0"
    annotationProcessor(
            "com.querydsl:querydsl-apt:5.0.0:jakarta",
            "jakarta.annotation:jakarta.annotation-api",
            "jakarta.persistence:jakarta.persistence-api"
    )
}

< ArticleRepositoryCustom >

public interface ArticleRepositoryCustom {
List\<String\> findAllDistinctHashtags();
}

< ArticleRepositoryCustomImpl >

public class ArticleRepositoryCustomImpl extends QuerydslRepositorySupport implements ArticleRepositoryCustom {

    public ArticleRepositoryCustomImpl() {
        super(Article.class);
    }
    
    @Override
    public List<String> findAllDistinctHashtags() {
        QArticle article = QArticle.article;
    
        return from(article)
                .select(article.hashtag)
                .fetch();
    }

}

< part of AticleService >

@Slf4j
@RequiredArgsConstructor // 필수 필드에 대한 생성자를 자동 생성
@Transactional
@Service                // 서비스 빈으로 등록
public class ArticleService {

    private final ArticleRepository articleRepository;
    
    // omit
    
    @Transactional(readOnly = true)
    public Page<ArticleDto> searchArticlesViaHashtag(String hashtag, Pageable pageable) {
        log.error("[해시태그 검색] Find Articles With Hashtag = {}", hashtag);
    
        if (hashtag == null || hashtag.isEmpty() || hashtag.isBlank()) {
            log.error("[해시태그 검색] Search Params is Null");
            return Page.empty(pageable);
        }
    
        return articleRepository.findByHashtag(hashtag, pageable).map(ArticleDto::from);
    }
    
    @Transactional(readOnly = true)
    public List<String> getHashtags() {
        List<String> uniqueHashtags = articleRepository.findAllDistinctHashtags();
        log.error("[유니크 해시태그 조회] uniqueHashtags = {}", uniqueHashtags);
        System.out.println(uniqueHashtags);
    
        return uniqueHashtags;
    }

< part of ArticleController >

@Slf4j
@RequiredArgsConstructor
@RequestMapping("/articles")
@Controller
public class ArticleController {

    private final ArticleService  articleService;
    private final PaginationService paginationService;

// omit

    @GetMapping("/search-hashtag")
    public String searchHashtag(
            @RequestParam(required = false) String searchValue,
            @PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable,
            ModelMap map
    ) {
        log.error("[컨트롤러] search-hashtag 확인, searchValue: {}", searchValue);
    
        Page<ArticleResponse> articles = articleService.searchArticlesViaHashtag(searchValue, pageable).map(ArticleResponse::from);
        log.error("[컨트롤러] searchArticlesViaHashtag에서 패스");
        
        List<Integer> barNumbers = paginationService.getPaginationBarNumbers(pageable.getPageNumber(), articles.getTotalPages());
        log.error("[컨트롤러] getPaginationBarNumbers에서 패스");
        
        List<String> hashtags = articleService.getHashtags();
        log.error("[컨트롤러] getHashtags에서 패스");
    
        log.error("[컨트롤러] articles: {}, barNumbers: {}, hashtag: {}", articles, barNumbers, hashtags);
    
        map.addAttribute("articles", articles);
        map.addAttribute("hashtags", hashtags);
        map.addAttribute("paginationBarNumbers", barNumbers);
        map.addAttribute("searchType", SearchType.HASHTAG);
    
        return "articles/search-hashtag";
    }

< error content >

2024-02-21T10:31:29.047+09:00 ERROR 18720 --- \[nio-8082-exec-1\] c.f.m.controller.ArticleController       : \[컨트롤러\] searchArticlesViaHashtag에서 패스
2024-02-21T10:31:29.049+09:00 ERROR 18720 --- \[nio-8082-exec-1\] c.f.m.controller.ArticleController       : \[컨트롤러\] getPaginationBarNumbers에서 패스
2024-02-21T10:31:29.094+09:00 ERROR 18720 --- \[nio-8082-exec-1\] o.a.c.c.C.\[.\[.\[/\].\[dispatcherServlet\]    : Servlet.service() for servlet \[dispatcherServlet\] in context with path \[\] threw exception \[Handler dispatch failed: java.lang.NoClassDefFoundError: javax/persistence/NoResultException\] with root cause

java.lang.ClassNotFoundException: javax.persistence.NoResultException
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) \~\[na:na\]
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) \~\[na:na\]
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520) \~\[na:na\]
at org.springframework.data.jpa.repository.support.Querydsl.createQuery(Querydsl.java:84) \~\[spring-data-jpa-3.1.8.jar:3.1.8\]
at org.springframework.data.jpa.repository.support.Querydsl.createQuery(Querydsl.java:100) \~\[spring-data-jpa-3.1.8.jar:3.1.8\]
at org.springframework.data.jpa.repository.support.QuerydslRepositorySupport.from(QuerydslRepositorySupport.java:110) \~\[spring-data-jpa-3.1.8.jar:3.1.8\]
at com.fastcampus.mvcboardproject.repository.querydsl.ArticleRepositoryCustomImpl.findAllDistinctHashtags(ArticleRepositoryCustomImpl.java:21) \~\[classes/:na\]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) \~\[na:na\]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) \~\[na:na\]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) \~\[na:na\]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) \~\[na:na\]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) \~\[spring-tx-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) \~\[spring-aop-6.0.16.jar:6.0.16\]
at com.fastcampus.mvcboardproject.repository.querydsl.ArticleRepositoryCustomImpl$$SpringCGLIB$$0.findAllDistinctHashtags(\<generated\>) \~\[classes/:na\]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) \~\[na:na\]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) \~\[na:na\]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) \~\[na:na\]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) \~\[na:na\]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:288) \~\[spring-data-commons-3.1.8.jar:3.1.8\]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:136) \~\[spring-data-commons-3.1.8.jar:3.1.8\]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:120) \~\[spring-data-commons-3.1.8.jar:3.1.8\]
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:516) \~\[spring-data-commons-3.1.8.jar:3.1.8\]
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:285) \~\[spring-data-commons-3.1.8.jar:3.1.8\]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:628) \~\[spring-data-commons-3.1.8.jar:3.1.8\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:168) \~\[spring-data-commons-3.1.8.jar:3.1.8\]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:143) \~\[spring-data-commons-3.1.8.jar:3.1.8\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:70) \~\[spring-data-commons-3.1.8.jar:3.1.8\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) \~\[spring-tx-6.0.16.jar:6.0.16\]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:391) \~\[spring-tx-6.0.16.jar:6.0.16\]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) \~\[spring-tx-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) \~\[spring-tx-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:164) \~\[spring-data-jpa-3.1.8.jar:3.1.8\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:244) \~\[spring-aop-6.0.16.jar:6.0.16\]
at jdk.proxy4/jdk.proxy4.$Proxy163.findAllDistinctHashtags(Unknown Source) \~\[na:na\]
at com.fastcampus.mvcboardproject.service.ArticleService.getHashtags(ArticleService.java:101) \~\[classes/:na\]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) \~\[na:na\]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) \~\[na:na\]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) \~\[na:na\]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) \~\[na:na\]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) \~\[spring-tx-6.0.16.jar:6.0.16\]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:391) \~\[spring-tx-6.0.16.jar:6.0.16\]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) \~\[spring-tx-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) \~\[spring-aop-6.0.16.jar:6.0.16\]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) \~\[spring-aop-6.0.16.jar:6.0.16\]
1

There are 1 best solutions below

0
Leti On

I finally fixed the error after two days of struggling. Here's my solution in case someone else faces the same problem:

Make sure to check the dependencies. I resolved the error by changing from

implementation "com.querydsl:querydsl-jpa"

to

implementation "com.querydsl:querydsl-jpa:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"

It seems that Querydsl couldn't locate the jakarta.persistence.api when only specifying implementation "com.querydsl:querydsl-jpa".

This adjustment worked for me. Have fun coding away, folks!