1

I have a spring boot application. I am trying to create a jar that will include some entities/controllers that I can pull in via dependency management (Maven) from our artifactory repository.

I'm confident this is a config/annotation thing, so only included those parts of my classes.

When I try to query the database for one of entities included in main application source I get an error about lack of Id field on the entity....

org.springframework.dao.InvalidDataAccessApiUsageException: Could not obtain identifier from MyEntity(id=1 ... <other fields> ...)

When I call one of APIs exposed by the external jar it retrieves from the database without error, any entities defined in the jar.

MyEntity (using Lombok):

@Entity
@ToString
@Slf4j
@EqualsAndHashCode
public class MyEntity
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    // removed other simple fields for brevity
 }

My main application class config:

@Slf4j
@EntityScan(basePackages = {"org.domain.matches.entity.location"})
@SpringBootApplication // same as @Configuration @EnableAutoConfiguration 
@ComponentScan
@ImportAutoConfiguration(value = { ConfigInExternalJar.class})
public class Boot extends SpringBootServletInitializer {
    public static void main(String[] args)
    {
        SpringApplication.run(Boot.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
    {
        return application.sources(Boot.class);
    }

    // some irrelevent debug stuff excluded
}

Additional config in main application:

@Slf4j
@Configuration
public class RestConfig implements RepositoryRestConfigurer, WebMvcConfigurer
{

Repository (others are very similar and fail in same way, missing id exception, but on their respective entity objects):

@RepositoryRestResource(collectionResourceRel = "my-entity", path = "my-entity")
public interface MyEntityRepository extends CrudRepository<MyEntity, Integer>
{
}

ConfigInExternalJar.java :

@ComponentScan(basePackages = { "org.domain.externaljar" })
@EnableJpaRepositories(basePackages = { "org.domain.externaljar" })
@EntityScan(basePackages = { "org.domain.externaljar" })
@Slf4j
@Configuration
public class ReferencesApiConfig {

Example entity in external jar:

@Entity
@Data
public class Reference
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Integer id;

    // removed other irrelevent fields

Stacktrace:

org.springframework.dao.InvalidDataAccessApiUsageException: Could not obtain identifier from MyEntity(id=1, version=2019_1_0, createdDate=2019-01-01, softwareVersion=null, softwareBuildDate=null)!; nested exception is java.lang.IllegalStateException: Could not obtain identifier from MyEntity(id=1, version=2019_1_0, createdDate=2019-01-01, softwareVersion=null, softwareBuildDate=null)!
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:370) ~[spring-orm-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:255) ~[spring-orm-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527) ~[spring-orm-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) ~[spring-tx-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242) ~[spring-tx-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153) ~[spring-tx-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) ~[spring-aop-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) ~[spring-data-commons-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at com.sun.proxy.$Proxy124.findAll(Unknown Source) ~[na:na]
at **org.domain.application.ApplicationListenerBean.onApplicationEvent(ApplicationListenerBean.java:47) ~[classes/:na]
at org.domain.application.ApplicationListenerBean.onApplicationEvent(ApplicationListenerBean.java:29) ~[classes/:na]**
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:402) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:359) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:896) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:163) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:552) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at org.lhasalimited.mirabilis.Boot.main(Boot.java:45) ~[classes/:na]

Caused by: java.lang.IllegalStateException: Could not obtain identifier from KnowledgeBase(id=1, version=2019_1_0, createdDate=2019-01-01, softwareVersion=null, softwareBuildDate=null)!
at org.springframework.data.mapping.TargetAwareIdentifierAccessor.getRequiredIdentifier(TargetAwareIdentifierAccessor.java:47) ~[spring-data-commons-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.springframework.data.jdbc.core.JdbcAggregateTemplate.publishAfterLoad(JdbcAggregateTemplate.java:251) ~[spring-data-jdbc-1.0.5.RELEASE.jar:1.0.5.RELEASE]
at org.springframework.data.jdbc.core.JdbcAggregateTemplate.findAll(JdbcAggregateTemplate.java:159) ~[spring-data-jdbc-1.0.5.RELEASE.jar:1.0.5.RELEASE]
at org.springframework.data.jdbc.repository.support.SimpleJdbcRepository.findAll(SimpleJdbcRepository.java:84) ~[spring-data-jdbc-1.0.5.RELEASE.jar:1.0.5.RELEASE]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[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:566) ~[na:na]
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359) ~[spring-data-commons-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200) ~[spring-data-commons-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644) ~[spring-data-commons-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608) ~[spring-data-commons-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595) ~[spring-data-commons-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595) ~[spring-data-commons-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) ~[spring-data-commons-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) ~[spring-tx-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) ~[spring-tx-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-5.1.5.RELEASE.jar:5.1.5.RELEASE]
... 24 common frames omitted
DaFoot
  • 1,475
  • 8
  • 29
  • 58
  • Which DB do you use? Think _GenerationType.IDENTITY_ works with MS SQL-SERVER but not with H2. Maybe you could use _GenerationType.AUTO_ then the provider automatically picks an appropriate strategy. – Dirk Deyne Jun 10 '19 at 12:05
  • Thanks for suggestion @DirkDeyne H2 or MySQL dependent on build. Switched to AUTO, same problem. – DaFoot Jun 10 '19 at 12:09
  • Can you please post the whole stacktrace? – Simon Martinelli Jun 11 '19 at 08:33
  • Stacktrace added. – DaFoot Jun 11 '19 at 08:55
  • do you have public getter/setter for id attribute ? – Benjamin Caure Jun 11 '19 at 09:03
  • Yes. Using Lombok, but have also tried with "real" get/set methods. – DaFoot Jun 11 '19 at 09:04
  • sorry for the dummy question : can you check @Id import (import javax.persistence.Id;) – Benjamin Caure Jun 11 '19 at 09:12
  • Not a dummy question at all. Have tried with both the javax annotation for Id and one from the Spring packages. Same result for both. – DaFoot Jun 11 '19 at 09:14
  • would it be possible that external jar defines a different persistence context than your own app? does the external jar include any configuration or is everything defined in you app? – Benjamin Caure Jun 11 '19 at 09:17
  • The external jar includes a couple of (at)Configuration annotated classes. Neither contain anything anymore other than (at)Configuration on the class and a no-arg constructor. application.properties file exists in jar, but everything is commented. I agree the context/entityManager being overwritten somehow by the jar is a possible, and is my primary suspicion right now, but I can't see that it would be creating one. – DaFoot Jun 11 '19 at 09:30
  • How does the code of ApplicationListenerBean look like and how does your repository look like? – Simon Martinelli Jun 11 '19 at 10:27
  • ApplicationListenerBean attempts to retrieve first 'MyEntity' from repository on ContextRefreshedEvent. This is where it fails at the moment. Take that call out and application starts up, when I hit an API URL I get the same error (missing Id) on the appropriate entity. I'll add repo code to question, but again I don't think this is the issue as problem is common to all Entity annotated classes/repos when I include my external jar. See issue only when include external jar. Hence thinking something in ext jar and annotations/dependencies/auto-spring, jar now almost entirely comments! – DaFoot Jun 11 '19 at 10:36
  • Let me ask you: Why do you have spring data jdbc in the project? I created a fresh one with only spring-boot-started-data-jpa, spring-boot-starter-data-rest and it is working fine. From the stacktrace, I don't understand why it is using jdbc behind – Brother Jun 11 '19 at 11:13
  • That is it, didn't need spring-boot-jdbc. Indeed when I take it out everything seems to work (it was probably left behind from some other stuff). I don't understand why presence of that lib would cause this issue, they are both spring-boot, but hey ho. @Brother if you create an answer to the question I'll give you your SO points. – DaFoot Jun 11 '19 at 11:44
  • Cool @DaFoot, thank you. I added the answer. – Brother Jun 11 '19 at 12:04

1 Answers1

2

So the problem was using the spring data jdbc at the same time as the spring data. It is clear the dependency in the stacktrace:

Caused by: java.lang.IllegalStateException: Could not obtain identifier from KnowledgeBase(id=1, version=2019_1_0, createdDate=2019-01-01, softwareVersion=null, softwareBuildDate=null)!
at org.springframework.data.mapping.TargetAwareIdentifierAccessor.getRequiredIdentifier(TargetAwareIdentifierAccessor.java:47) ~[spring-data-commons-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.springframework.data.jdbc.core.JdbcAggregateTemplate.publishAfterLoad(JdbcAggregateTemplate.java:251) ~[spring-data-jdbc-1.0.5.RELEASE.jar:1.0.5.RELEASE]
at org.springframework.data.jdbc.core.JdbcAggregateTemplate.findAll(JdbcAggregateTemplate.java:159) ~[spring-data-jdbc-1.0.5.RELEASE.jar:1.0.5.RELEASE]
at org.springframework.data.jdbc.repository.support.SimpleJdbcRepository.findAll(SimpleJdbcRepository.java:84) ~[spring-data-jdbc-1.0.5.RELEASE.jar:1.0.5.RELEASE]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[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:566) ~[na:na]
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359) ~[spring-data-commons-2.1.5.RELEASE.jar:2.1.5.RELEASE]

Here:

spring-data-jdbc-1.0.5.RELEASE.jar:1.0.5.RELEASE

After removed the dependency, all seems to work again.

Brother
  • 2,150
  • 1
  • 20
  • 24