MelRanG
729
2021-08-23 23:40:37 작성 2021-08-23 23:44:35 수정됨
7
277

JPA @MappedSuperclass 에서 builder관련 질문드립니다.


안녕하십니까 @MappedSuperclass 관련 두 가지 문제가 생겨서 질문드립니다.


1.

현재 선호제품과 비선호제품 테이블이 있고 두 테이블의 칼럼은 id, name, image로 같습니다.

선호제품savdDto, 비선호제품saveDto 이런식으로 분할된 클래스를 제품SaveDto로 같이 묶는 것이 목적입니다.


두 테이블의 칼럼이 같으니 @MapperdSuperclass를 검색해보라는 글을 보고 해결하다 builder에서 막혔습니다.

id, name, image가 같으니 BaseProductEntity에 모두 선언하고 그것을 구현??한 FavoriteProduct와 UnFavorableProduct에서 사용하는데 builder는 어떻게 처리해야할까요?

@Getter
@NoArgsConstructor
@Entity
public class FavoriteProduct extends BaseProductEntity {

@Builder
public FavoriteProduct(String userId, String productName, String image){

}

}


빌더에 구현체가 없어 테스트를 진행하니 null값이 뜨고 super를 사용하니 또 에러가 발생합니다... 두 Dto를 통합하려면 @MapperdSuperclass가 아니라 다른 방법을 사용해야할까요??


@Getter
@MappedSuperclass
public class BaseProductEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String userId;

private String productName;

private String image;


}


2.

앞서 언급한  선호제품savdDto, 비선호제품saveDto 를 합치는 과정에서 builder로 삽입하려고 합니다.

두 Dto를 합치려면 FavoriteProduct빌더와 UnFavorableProduct빌더를 Product빌더로 바꿔서 처리해야하는데 도저히 방법이 생각나지 않습니다.

그래서 두 개의 칼럼은 같으니 FavoriteProduct로 받아놓고 save할 때 UnFavorableProduct에도 삽입해도 되는지요??



0
  • 답변 7

  • 초무쿤
    6k
    2021-08-24 02:23:18 작성 2021-08-24 02:23:48 수정됨

    FavoriteProduct에

    @EqualsAndHashCode(callSuper=false)

    를 한번 넣어보시쥬.

    @Builder때문에 나는 오류가 아닌듯 합니다.

  • 클라우디오
    209
    2021-08-24 10:30:12

    extends한 클래스의 부모 클래스의 멤버변수를 builder패턴으로 접근하려면 @Builder 대신에 @SuperBuilder를 사용하셔야 정상적으로 처리가 됩니다. 해당 키워드로 검색해보시는게 좋을 것 같네요.

  • MelRanG
    729
    2021-08-24 14:27:43

    클라우디오

    알려주신 키워드로 검색해서 처리하려니 같은 문제가 반복돼서 답을 찾기 못해 다시 질문드립니다 ㅠㅠ

    @Getter
    @MappedSuperclass
    @SuperBuilder
    public class BaseProductEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String userId;

    private String productName;

    private String image;

    }


    @Entity
    @SuperBuilder
    public class FavoriteProduct extends BaseProductEntity {

    }


    Entity클래스에 기본 생성자가 필요하다는 에러가 발생해서 기본 생성자를 만들면 기본 생성자안에 super()를 사용하라는 메시지가 뜹니다.

    super()를 넣고 안에 String타입의 변수를 넣으니 에러가 발생해

    BaseProductEntityBuilder타입으로 넣었습니다.

    public FavoriteProduct(BaseProductEntityBuilder baseProduct){
    super(baseProduct);
    };


    이 방법을 사용하니 기본 생성자 클래스인 public FavoriteProduct에 should have [public, protected] no-arg constructor 에러가 발생합니다. 이 과정에서 도저히 해결법을 찾기 못해서 다시 질문드립니다!

  • 클라우디오
    209
    2021-08-24 14:45:06
    올려주신 소스대로 테스트로 작성 해 봤는데, IDE에서는 별도로 오류를 잡지는 않더라구요. 혹시 실행할때 에러가 발생하는건가요? 에러메세지 전체와 소스를 자세히 올려주시는게 도움이 될 것 같습니다.
  • MelRanG
    729
    2021-08-24 14:56:43

    클라우디오

    감사합니다! 

    초기 클래스명은 Product였는데 지금은 Perfume으로 변경되었고 나머지는 같습니다

    우선 소스와 테스트코드먼저 올리고 오류메시지를 올리겠습니다.


    FavoritePerfume

    import com.patrick.perfume.domain.BasePerfumeEntity;
    import lombok.experimental.SuperBuilder;

    import javax.persistence.Entity;



    @Entity
    @SuperBuilder
    public class FavoritePerfume extends BasePerfumeEntity {

    }

    FavoritePerfumeRepository

    public interface FavoritePerfumeRepository extends JpaRepository<FavoritePerfume, Long> {
    }

    BasePerfumeEntity

    @Getter
    @MappedSuperclass
    @SuperBuilder
    public class BasePerfumeEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String userId;

    private String perfumeName;

    private String image;

    }

    FavoritePerfumeTest

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class FavoritePerfumeTest {
    @Autowired
    FavoritePerfumeRepository favoriteRepo;

    @Test
    public void Favorite_저장테스트(){
    favoriteRepo.save(FavoritePerfume.builder()
    .userId("aa")
    .perfumeName("bb")
    .image("cc")
    .build());

    List<FavoritePerfume> perfumes = favoriteRepo.findAll();

    FavoritePerfume favoritePerfume = perfumes.get(0);
    assertThat(favoritePerfume.getUserId()).isEqualTo("aa");
    }

    }


    실행하기 전 FavoritePerfume에 뜨는 에러

    Class 'FavoritePerfume' should have [public, protected] no-arg constructor



    실행 후 테스트에 뜨는 에러

    No default constructor for entity:  : com.patrick.perfume.domain.favoriteperfume.FavoritePerfume; nested exception is org.hibernate.InstantiationException: No default constructor for entity:  : com.patrick.perfume.domain.favoriteperfume.FavoritePerfume

    org.springframework.orm.jpa.JpaSystemException: No default constructor for entity:  : com.patrick.perfume.domain.favoriteperfume.FavoritePerfume; nested exception is org.hibernate.InstantiationException: No default constructor for entity:  : com.patrick.perfume.domain.favoriteperfume.FavoritePerfume

    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:351)

    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:253)

    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527)

    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)

    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)

    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153)

    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)

    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:144)

    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)

    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$ExposeRepositoryInvocationInterceptor.invoke(CrudMethodMetadataPostProcessor.java:364)

    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)

    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)

    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)

    at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)

    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)

    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)

    at com.sun.proxy.$Proxy118.findAll(Unknown Source)

    at com.patrick.perfume.domain.preferenceperfume.FavoritePerfumeTest.Favorite_저장테스트(FavoritePerfumeTest.java:28)

    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.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)

    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)

    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)

    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)

    at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)

    at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)

    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)

    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)

    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)

    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)

    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)

    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)

    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)

    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)

    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)

    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)

    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)

    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)

    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)

    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)

    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)

    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:106)

    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)

    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)

    at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:66)

    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)

    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.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)

    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)

    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)

    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)

    at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)

    at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:117)

    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.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)

    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)

    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:155)

    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:137)

    at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)

    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)

    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)

    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)

    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)

    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)

    at java.lang.Thread.run(Thread.java:748)

    Caused by: org.hibernate.InstantiationException: No default constructor for entity:  : com.patrick.perfume.domain.favoriteperfume.FavoritePerfume

    at org.hibernate.tuple.PojoInstantiator.instantiate(PojoInstantiator.java:85)

    at org.hibernate.tuple.PojoInstantiator.instantiate(PojoInstantiator.java:105)

    at org.hibernate.tuple.entity.AbstractEntityTuplizer.instantiate(AbstractEntityTuplizer.java:673)

    at org.hibernate.persister.entity.AbstractEntityPersister.instantiate(AbstractEntityPersister.java:4950)

    at org.hibernate.internal.SessionImpl.instantiate(SessionImpl.java:1682)

    at org.hibernate.internal.SessionImpl.instantiate(SessionImpl.java:1666)

    at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1663)

    at org.hibernate.loader.Loader.getRow(Loader.java:1561)

    at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:731)

    at org.hibernate.loader.Loader.processResultSet(Loader.java:990)

    at org.hibernate.loader.Loader.doQuery(Loader.java:948)

    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:340)

    at org.hibernate.loader.Loader.doList(Loader.java:2689)

    at org.hibernate.loader.Loader.doList(Loader.java:2672)

    at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2506)

    at org.hibernate.loader.Loader.list(Loader.java:2501)

    at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:504)

    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:395)

    at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:220)

    at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1508)

    at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1537)

    at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1505)

    at org.hibernate.query.Query.getResultList(Query.java:132)

    at org.hibernate.query.criteria.internal.compile.CriteriaQueryTypeQueryAdapter.getResultList(CriteriaQueryTypeQueryAdapter.java:74)

    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll(SimpleJpaRepository.java:346)

    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.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359)

    at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200)

    at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644)

    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)

    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608)

    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)

    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)

    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)

    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)

    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)

    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295)

    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)

    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)

    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)

    ... 67 more







    com.patrick.perfume.domain.preferenceperfume.FavoritePerfumeTest > Favorite_저장테스트 FAILED

        org.springframework.orm.jpa.JpaSystemException at FavoritePerfumeTest.java:28

            Caused by: org.hibernate.InstantiationException at FavoritePerfumeTest.java:28

    2021-08-24 14:52:17.226  INFO 17240 --- [       Thread-5] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'



    2021-08-24 14:52:17.233  INFO 17240 --- [       Thread-5] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'

    2021-08-24 14:52:17.234  INFO 17240 --- [       Thread-5] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed evictData of schema as part of SessionFactory shut-down'




    감사합니다!


  • MelRanG
    729
    2021-08-24 15:03:47

    안에 빈 생성자를 넣었을 때 발생하는 에러

    import com.patrick.perfume.domain.BasePerfumeEntity;
    import lombok.experimental.SuperBuilder;

    import javax.persistence.Entity;



    @Entity
    @SuperBuilder
    public class FavoritePerfume extends BasePerfumeEntity {
    public FavoritePerfume(){};
    }


    error: constructor BasePerfumeEntity in class BasePerfumeEntity cannot be applied to given types;

        public FavoritePerfume(){};

                                ^

      required: BasePerfumeEntityBuilder<?,?>

      found: no arguments

      reason: actual and formal argument lists differ in length

    1 error


    FAILURE: Build failed with an exception.


    * What went wrong:

    Execution failed for task ':compileJava'.

    > Compilation failed; see the compiler error output for details.



    이 상태에서 마우스를 publicFavoritePerfume에 가져다대면 super()를 넣으라고 뜹니다.
    이렇게 super를 넣으면
    @Entity
    @SuperBuilder
    public class FavoritePerfume extends BasePerfumeEntity {
    public FavoritePerfume(BasePerfumeEntityBuilder baseProduct){
    super(baseProduct);
    };
    }

    No default constructor for entity:  : com.patrick.perfume.domain.favoriteperfume.FavoritePerfume; nested exception is org.hibernate.InstantiationException: No default constructor for entity:  : com.patrick.perfume.domain.favoriteperfume.FavoritePerfume
    org.springframework.orm.jpa.JpaSystemException: No default constructor for entity:

    이렇게 첫번쨰 에러가 비슷한 에러가 발생합니다

  • MelRanG
    729
    2021-08-24 15:38:23

    클라우디오

    도움 주셔서 감사합니다 그동안 한쪽 클래스에만 생성자를 생성해봤는데 양쪽 다 

    @NoArgsConstructor

    추가하니 에러가 해결됐습니다!

  • 로그인을 하시면 답변을 등록할 수 있습니다.