5

I have this class in QuoteProjection.java:

package com.mycompany.myapp.query;

import com.mycompany.myapp.command.domain.ProjectedQuote;
import javax.persistence.EntityManager;

public class QuoteProjection {

    private final EntityManager entityManager;
.
.
.
    public void on(CreateSubmissionEvt evt) {
        ProjectedQuote projectedQuote = new ProjectedQuote(evt.getAggregateId(), evt.getJobNumber());
        entityManager.persist(projectedQuote); // error reference this line
    }

I've defined ProjectedQuote in myApi.kt:

package com.mycompany.myapp.command.domain

@Entity
@NamedQueries(
        NamedQuery(name = "ProjectedQuote.fetch",
                query = "SELECT q FROM ProjectedQuote q WHERE q.aggregateId LIKE CONCAT(:idStartsWith, '%') ORDER BY q.id"),
        NamedQuery(name = "ProjectedQuote.count",
                query = "SELECT COUNT(q) FROM ProjectedQuote q WHERE q.aggregateId LIKE CONCAT(:idStartsWith, '%')")
)
data class ProjectedQuote(@Id var aggregateId: String, var jobNumber : String) { constructor() : this("", "") }

When running, I get the following error:

java.lang.IllegalArgumentException: Unknown entity:
com.mycompany.myapp.command.domain.ProjectedQuote
        at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:787) ~hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]
        at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:768) ~[hibernate-core-5.2.17.Final.jar!/:5.2.17.Final]
.
.
.

Per Lesiak's answer below, I tried adding @EntityScan to the application, Application.java:

package com.mycompany.myapp.query;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;

@SpringBootApplication
@EntityScan(basePackages = {"com.mycompany.myapp.command.domain"})
public class Application {
  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
}

...but now I get the following error and the application terminates:

2019-04-16 15:34:54.265 ERROR 4212 --- [           main] o.s.boot.SpringApplication
          : Application run failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sagaStore' defined in class path resource [org/axonframework/springboot/autoconfig/JpaAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.axonframework.modelling.saga.repository.jpa.JpaSagaStore]: Factory method 'sagaStore' threw exception; nested exception is java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: SagaEntry is not mapped [SELECT new org.axonframework.modelling.saga.repository.jpa.SerializedSaga(se.serializedSaga, se.sagaType, se.revision) FROM SagaEntry se WHERE se.sagaId = :sagaId]
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:590) ~[spring-beans-5.0.9.RELEASE.jar!/:5.0.9.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1247) ~[spring-beans-5.0.9.RELEASE.jar!/:5.0.9.RELEASE]
.
.
.

Sagas, referenced in the error message, are part of the Axon Framework. So by doing an @EntityScan on my packages, it looks like it caused it to NOT scan the Axon packages, maybe?

I'm in over my head. Any help is appreciated.

Jonathan M
  • 17,145
  • 9
  • 58
  • 91
  • Are you familiar with the basics of pure-Java JPA? Are you using the Kotlin JPA plugin? – chrylis -cautiouslyoptimistic- Apr 15 '19 at 21:44
  • @chrylis, I'm pretty new to JPA in all forms: Java and Kotlin. No plugins in use. – Jonathan M Apr 15 '19 at 21:46
  • check your `persistence.xml`, your entity must be mapped to datasource or all entities must be automatically mapped by config – Ioseb Khutsishvili Apr 15 '19 at 21:51
  • @Ioseb, I don't have a persistence.xml, as I'm copying from a working example which doesn't have one. Is it required? – Jonathan M Apr 15 '19 at 21:54
  • @JonathanM is this spring app or regular java/hibernate project ? – Ioseb Khutsishvili Apr 15 '19 at 21:56
  • @Ioseb it's a Spring app. – Jonathan M Apr 15 '19 at 21:57
  • @JonathanM make sure `ProjectedQuote` class has `@Entity` annotation – Ioseb Khutsishvili Apr 15 '19 at 21:59
  • JPA has a number of specific requirements on entity classes, and entity types also need to be registered with the provider (Hibernate in this case; Spring `@EntityScan` is the best option for you). I would suggest learning JPA with plain Java, but if that's not an option, you definitely need the JPA plugin to override some Kotlin defaults that aren't compatible with the JPA model. – chrylis -cautiouslyoptimistic- Apr 16 '19 at 02:17
  • @IosebKhutsishvili, it turns out there was an `@Entity` annotation. Please see my update above. Sorry for the confusion. – Jonathan M Apr 16 '19 at 14:48
  • @chrylis, I'll dive into that. I'm a bit confused because the working example I have (the Axon gift card demo) does what I'm trying to do, and it does so without `@EntityScan` or other efforts. It just uses `@Entity`. The applicable code from the gift card demo is here: https://github.com/AxonIQ/giftcard-demo/blob/master/src/main/java/io/axoniq/demo/giftcard/api/api.kt – Jonathan M Apr 16 '19 at 14:53
  • By default, Spring Boot's starters will generally scan the main class's package recursively for components, entities, repositories, and other stuff. I always put it in its own separate package and so need `@EntityScan`. – chrylis -cautiouslyoptimistic- Apr 16 '19 at 18:04
  • @chrylis, ah, yes, that is the difference between the working example and my app. The working example has the entities in the same package as the application, but mine has them in different packages. Much thanks. – Jonathan M Apr 16 '19 at 19:09
  • @chrylis, I've added `@EntityScan(basePackages={"com.mycompany.myapp.query", "com.mycompany.myapp.command.domain"})` to my application, but I'm getting immediate runtime errors now: "org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sagaStore' defined in class path resource [org/axonframework/springboot/autoconfig/JpaAutoConfiguration.class]: Bean instantiation via factory method failed..." It appears that this has broken some Axon stuff. – Jonathan M Apr 16 '19 at 19:21

1 Answers1

4

How about annotating your class with @Entity

See for example https://docs.jboss.org/hibernate/annotations/3.5/reference/en/html/entity.html#entity-mapping-entity

Update

Check which entities are scanned. https://springbootdev.com/2017/11/13/what-are-the-uses-of-entityscan-and-enablejparepositories-annotations/amp/

By default, Spring Boot will enable entity scanning and look in the package (and its subpackages) where @SpringBootApplication is located. If your configuration has entities in another package, use @EntityScan

Update 2

After some investigation, it turned out that the question is very Axon-specific.

Axon needs to register its own entities, like SagaEntry mentioned in the updated question. It registers these entities in JpaAutoConfiguration To do so, it uses its own annotation @RegisterDefaultEntities Unfortunately their configuration works well if you rely on the default project layout (domain models in a sub-package of a package containing your app), but doesn't play nice with @EntityScan

Check issue https://github.com/AxonFramework/AxonFramework/issues/245

My advice is to repackage your application (move entitiees to a sub-package if your app package) and remove @EntityScan

If you are adventurous, you can try scaning the same packages that are scanned by their custom annotation, but I am not sure if this will succeed.

Jonathan M
  • 17,145
  • 9
  • 58
  • 91
Lesiak
  • 22,088
  • 2
  • 41
  • 65
  • Wondered about that, but had a working example that did not have the @Entity (though it appeared on the structure above it). Is there a doc you can point me to? – Jonathan M Apr 15 '19 at 21:45
  • Did it have XML mapping? – Lesiak Apr 15 '19 at 21:51
  • I've not created any because my working example didn't have any either. Is it required? – Jonathan M Apr 15 '19 at 21:52
  • No, not at all. It was used before annotations were introduced to Java. Just guessing why your example worked without the annotation. – Lesiak Apr 15 '19 at 21:54
  • Gotcha. I'll try the annotation. – Jonathan M Apr 15 '19 at 21:55
  • @Lesiak, you were right, but it turns out I already have the `@Entity` annotation in the code. Please take a look at my update in the original question above. Any additional insights are appreciated. – Jonathan M Apr 16 '19 at 14:54
  • @Lesiak, I've added `@EntityScan(basePackages={"com.mycompany.myapp.query", "com.mycompany.myapp.command.domain"})` to my application, but I'm getting immediate runtime errors now: "org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sagaStore' defined in class path resource [org/axonframework/springboot/autoconfig/JpaAutoConfiguration.class]: Bean instantiation via factory method failed..." It appears that this has broken some Axon stuff. – Jonathan M Apr 16 '19 at 19:36
  • Where is your app in the package hierarchy? Does removing the EntityScan and relying on the default solves the issue? It looks like someone had exactly same issue https://github.com/AxonFramework/AxonFramework/issues/245 – Lesiak Apr 16 '19 at 20:41
  • @Lesiak, I've added some updates to the question. My app is in `com.mycompany.myapp.query`. Removing the `@EntityScan` only gets me back to my original error of `Unknown Entity`. – Jonathan M Apr 16 '19 at 20:43
  • Put your app in com.mycompany.myapp, this should do the trick. (Entityscan removed) – Lesiak Apr 16 '19 at 20:47
  • Yes, but the myapp portion of the package name is actually host to four apps - query, command, ui, uiserver. Thus we've put each into its own space. Is there no way to make JPA recognize entities in multiple packages? Isn't that the purpose of @EntityScan? – Jonathan M Apr 16 '19 at 20:53
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/191940/discussion-between-lesiak-and-jonathan-m). – Lesiak Apr 16 '19 at 20:56