복붙노트

[SPRING] IllegalArgumentException : 형태를 null로 할 수 없다

SPRING

IllegalArgumentException : 형태를 null로 할 수 없다

나는 문제에 직면하고 있으며, 많은 사람들이 그것을 겪어서 아마도 그것을 해결할 수 없었던 것으로 보인다.

다음 MYSQL 저장 프로 시저가 있습니다. 이것은 모든 것이 잘 작동 하는지를보기위한 샘플 일뿐입니다. 그런 다음 비활성과 같은 매개 변수를 추가하기 시작했습니다.

CREATE DEFINER=`root`@`localhost` PROCEDURE `get_resource_types`()
BEGIN
    SELECT *
    FROM resource_types
    WHERE inactive = 0;
END

resource_types 테이블과 명명 된 저장 프로 시저 쿼리를 매핑하는 엔터티.

@NamedStoredProcedureQuery(
        name="getResourceTypes",
        procedureName="get_resource_types",
        resultClasses = ResourceType.class,
        parameters = {}
)
@Entity
@Table(name = "resource_types")
public class ResourceType {
    ... fields with annotations used for validation + getters and setters ...
}

그리고 여기에 저장 프로 시저를 호출하는 JpaRepository가 있습니다.

@Repository
public interface ResourceTypeRepository extends JpaRepository<ResourceType, Long> {
    @Procedure("ResourceType.getResourceTypes")
    List<ResourceType> getResourceTypes();

}

@Service에있는 getAll () 메서드

public List<ResourceType> getAll(){
    final List<ResourceType> resourceTypes = resourceTypeRepository.getResourceTypes();
    return resourceTypes;
}

이것을 실행하려고하면 다음 스택 추적을 얻습니다.

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: Type cannot be null; nested exception is java.lang.IllegalArgumentException: Type cannot be null
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:618)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
    at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:65)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
    at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167)
    at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
    at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:144)
    at com.test.ihbs.controller.ResourceTypeControllerTest.test_getAll(ResourceTypeControllerTest.java:111)
    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:497)
    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.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:73)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:224)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
    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:68)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:86)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:49)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:64)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:50)
    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:497)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
    at org.gradle.messaging.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:106)
    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:497)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:360)
    at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: Type cannot be null; nested exception is java.lang.IllegalArgumentException: Type cannot be null
    at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:381)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:223)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:417)
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.java:122)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
    at com.sun.proxy.$Proxy87.getResourceTypes(Unknown Source)
    at com.ihbs.service.ResourceTypeService.getAll(ResourceTypeService.java:34)
    at com.ihbs.controller.ResourceTypeController.getAllResourceTypes(ResourceTypeController.java:44)
    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:497)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:776)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
    ... 58 more
Caused by: java.lang.IllegalArgumentException: Type cannot be null
    at org.hibernate.procedure.internal.AbstractParameterRegistrationImpl.setHibernateType(AbstractParameterRegistrationImpl.java:182)
    at org.hibernate.procedure.internal.AbstractParameterRegistrationImpl.<init>(AbstractParameterRegistrationImpl.java:131)
    at org.hibernate.procedure.internal.AbstractParameterRegistrationImpl.<init>(AbstractParameterRegistrationImpl.java:140)
    at org.hibernate.procedure.internal.AbstractParameterRegistrationImpl.<init>(AbstractParameterRegistrationImpl.java:77)
    at org.hibernate.procedure.internal.PositionalParameterRegistration.<init>(PositionalParameterRegistration.java:41)
    at org.hibernate.procedure.internal.ProcedureCallImpl.registerParameter(ProcedureCallImpl.java:275)
    at org.hibernate.jpa.internal.StoredProcedureQueryImpl.registerStoredProcedureParameter(StoredProcedureQueryImpl.java:128)
    at org.springframework.data.jpa.repository.query.StoredProcedureJpaQuery.newAdhocStoredProcedureQuery(StoredProcedureJpaQuery.java:147)
    at org.springframework.data.jpa.repository.query.StoredProcedureJpaQuery.createStoredProcedure(StoredProcedureJpaQuery.java:110)
    at org.springframework.data.jpa.repository.query.StoredProcedureJpaQuery.doCreateQuery(StoredProcedureJpaQuery.java:68)
    at org.springframework.data.jpa.repository.query.StoredProcedureJpaQuery.createQuery(StoredProcedureJpaQuery.java:58)
    at org.springframework.data.jpa.repository.query.JpaQueryExecution$ProcedureExecution.doExecute(JpaQueryExecution.java:295)
    at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:74)
    at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:97)
    at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:88)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:395)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:373)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$DefaultMethodInvokingMethodInterceptor.invoke(RepositoryFactorySupport.java:486)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
    ... 80 more

어떤 아이디어가 왜 이런 일이 일어나고 어떻게 해결할 수 있습니까?

InvalidDataAccessApiUsageException에 대한 설명서 :

업데이트 1

저장소를 다음 코드로 변경하면 작동 할 것입니다. 즉 이름 프로 시저 쿼리에 문제가 있음을 의미합니다. 나는 아직도 저장 프로 시저가 작동하도록해야한다.

@Repository
public interface ResourceTypeRepository extends JpaRepository<ResourceType, Long> {

    @Query("SELECT rt FROM ResourceType rt WHERE rt.inactive = 0")
    List<ResourceType> getResourceTypes();

}

업데이트 2

나는 EclipseLink를 사용하지 않고있다. (또는 적어도 나는 그의 존재에 대해 모른다.)

업데이트 3

디버깅을하더라도이 문제의 원인을 찾을 수 없습니다. 그러나 문제를 찾는 데 도움이 될만한 것을 발견했습니다.

org / springframework / data / jpa / repository / query / StoredProcedureJpaQuery.java에서이 코드 조각을 발견했습니다. 그리고 마지막 줄에 총 매개 변수 개수를 가져온 함수에 대한 호출이 있음을 알 수 있습니다. 여분의 것. 여기에 여분의 매개 변수 인 문제가있을 수 있습니다. 하지만 상황에 따라 다른 경로를 따라 갈 수 있다고 가정하기 때문에 문제가되지 않을 수 있습니다.

/**
 * Extracts the output value from the given {@link StoredProcedureQuery}.
 * 
 * @param storedProcedureQuery must not be {@literal null}.
 * @return
 */
Object extractOutputValue(StoredProcedureQuery storedProcedureQuery) {

    Assert.notNull(storedProcedureQuery, "StoredProcedureQuery must not be null!");

    if (!procedureAttributes.hasReturnValue()) {
        return null;
    }

    if (StringUtils.hasText(procedureAttributes.getOutputParameterName())) {
        return storedProcedureQuery.getOutputParameterValue(procedureAttributes.getOutputParameterName());
    }

    return storedProcedureQuery.getOutputParameterValue(getQueryMethod().getParameters().getNumberOfParameters() + 1);
}

해결법

  1. ==============================

    1.1.11.1 현재의 Spring Data JPA는 결과 집합을 반환하는 SP를 지원하지 않습니다. Spring Data에 해당하는 결함을 제출했습니다.

    1.11.1 현재의 Spring Data JPA는 결과 집합을 반환하는 SP를 지원하지 않습니다. Spring Data에 해당하는 결함을 제출했습니다.

    해결책은 API 레벨을 내리고 JPA 만 사용하는 것입니다. 여기에 MS SQL SP와 함께 작동하는 쓴 일반 클래스가 있습니다.

    import com.google.common.base.Strings;
    import java.util.List;
    import javax.persistence.EntityManager;
    import javax.persistence.ParameterMode;
    import javax.persistence.Query;
    import javax.persistence.StoredProcedureQuery;
    import lombok.RequiredArgsConstructor;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    @Service
    @RequiredArgsConstructor(onConstructor = @__(@Autowired))
    public class StoredProcRepository {
    
      //region Injected beans (via a RequiredArgsConstructor)
      private final EntityManager em;
      //endregion 
    
      /**
       * Calls a stored procedure via JPA and retrieves a single implicit result set (in DBs that
       * support them e.g. MS SQL or MySQL). The call is not dependent on a DB dialect. Be
       * aware that large result sets should be paginated and not entirely read to memory. Recreates
       * StoredProcedureQuery instance and its parameters on each call.
       * To execute MS SQL SPs performing multiple queries, SET NOCOUNT ON.
       *
       * @param procedureName stored procedure name, optionally qualified per DB syntax
       * @param resultClass converts (maps) each result set row into instances of resultClass via JPA
       * @param spArgs stored procedure arguments, supplied positionally (optional SP arguments at the
       * end of the list could be omitted)
       * @param <T> class of row instances converted per JPA
       * @return the entire result set
       */
      public <T> List<T> queryViaStoredProc(String procedureName, Class<T> resultClass,
          Object... spArgs) {
        StoredProcedureQuery spq = em.createStoredProcedureQuery(procedureName, resultClass);
        int pos = 0;
        for (Object arg : spArgs) {
          spq.registerStoredProcedureParameter(++pos, arg.getClass(), ParameterMode.IN);
          spq.setParameter(pos, arg);
        }
        return spq.getResultList();
      }
    
      /**
       * Calls a stored procedure via JPA and retrieves only the top row of a single implicit result
       * set (in DBs that support them e.g. MS SQL or MySQL).
       * Assumes that result set has at least one row.
       * The call is not dependent on a DB dialect.
       * Be aware that large result sets should be paginated and not entirely read to memory.
       * Recreates StoredProcedureQuery instance and its parameters on each call.
       * To execute MS SQL SPs performing multiple queries, SET NOCOUNT ON.
       *
       * @param procedureName stored procedure name, optionally qualified per DB syntax
       * @param resultClass converts (maps) each result set row into instances of resultClass via JPA
       * @param spArgs stored procedure arguments, supplied positionally (optional SP arguments at the
       * end of the list could be omitted)
       * @param <T> class of row instances converted per JPA
       * @return the entire result set
       */
      public <T> T queryTopRowViaStoredProc(String procedureName, Class<T> resultClass,
          Object... spArgs) {
        return queryViaStoredProc(procedureName, resultClass, spArgs).get(0);
      }
    }
    

    MS SQL SP의 경우 추가 요구 사항은 둘 이상의 쿼리를 실행하는 모든 SP에 대해 SET NOCOUNT ON을 설정하는 것입니다. 최소한 다음 세 가지 방법 중 하나로 설정할 수 있습니다.

    그녀는 # 1 : 동일한 StoredProcRepository 클래스에 해당하는 메소드의 코드입니다.

      /**
       * Calls an MS SQL stored procedure via JPA and retrieves a single implicit result set.
       * Protects against lack of SET NOCOUNT in stored procedures.
       * This works with jTDS JDBC driver, but not with MS JDBC driver.
       * Be aware that large result sets should be paginated and not entirely read to memory.
       *
       * @param procedureName stored procedure name, optionally qualified per DB syntax
       * @param resultClass converts (maps) each result set row into instances of resultClass via JPA
       * @param spArgs stored procedure arguments, supplied positionally (optional SP arguments at the
       * end of the list could be omitted)
       * @param <T> class of row instances converted per JPA
       * @return the entire result set
       */
      public <T> List<T> queryViaMsSqlStoredProc(String procedureName, Class<T> resultClass,
          Object... spArgs) {
        String spBindParams = (spArgs.length == 0) ? "" : "?" + Strings.repeat(",?", spArgs.length - 1);
    
        // The following works with jTDS driver, but not with MS driver
        String spQuery = String.format("EXEC %s %s", procedureName, spBindParams);
    
        // The following works with jTDS driver, but not with MS driver
        /*
        String spQuery = String.format("{call %s(%s)}", procedureName, spBindParams);
        Query q = em.createNativeQuery("SET NOCOUNT ON; " + spQuery, resultClass)
            .setHint("org.hibernate.readOnly", true);
        */
    
        Query q = em.createNativeQuery(spQuery, resultClass);
        int pos = 0;
        for (Object arg : spArgs) {
          q.setParameter(++pos, arg);
        }
        return q.getResultList();
      }    
    
      /**
       * Calls an MS SQL stored procedure via JPA and retrieves only the top row of a single implicit
       * result set.
       * Assumes that result set has at least one row.
       * The call sets the "NOCOUNT ON" MS SQL batch option.
       * Be aware that large result sets should be paginated and not entirely read to memory.
       *
       * @param procedureName stored procedure name, optionally qualified per DB syntax
       * @param resultClass converts (maps) each result set row into instances of resultClass via JPA
       * @param spArgs stored procedure arguments, supplied positionally (optional SP arguments at the
       * end of the list could be omitted)
       * @param <T> class of row instances converted per JPA
       * @return the entire result set
       */
      public <T> T queryTopRowViaMsSqlStoredProc(String procedureName, Class<T> resultClass,
          Object... spArgs) {
        return queryViaMsSqlStoredProc(procedureName, resultClass, spArgs).get(0);
      }
    
  2. ==============================

    2.문제는 결과 매핑 (결과 엔티티를 입력 할 수없는 경우) 인 것 같습니다.

    문제는 결과 매핑 (결과 엔티티를 입력 할 수없는 경우) 인 것 같습니다.

    변경해보십시오.

    @Procedure("ResourceType.getResourceTypes")
    List<ResourceType> getResourceTypes();
    

    @Procedure("ResourceType.getResourceTypes")
    Object[] getResourceTypes();
    

    NamedStoredProcedureQuery에서 resultClasses를 제거하십시오.

    희망이 도움이됩니다.

  3. from https://stackoverflow.com/questions/31097667/illegalargumentexception-type-cannot-be-null by cc-by-sa and MIT license