katharsis-project / katharsis-framework

Katharsis adds powerful layer for RESTful endpoints providing implementenation of JSON:API standard
http://katharsis.io
Apache License 2.0
135 stars 65 forks source link

How to set resource type for jpa entity? #416

Open exports opened 7 years ago

exports commented 7 years ago

I try to set the resource type for a jpa entity with @JsonApiResource in katharsis-jpa, but it does not work.

loickR commented 7 years ago

I've the same problem, when I declare my entities with @JsonApiResource annotation, it seems katharsis ignore them or does not apply mapping type specified. The github "spring-boot-examples" repository show an example to implement a specific JpaMapper in order to have two classes : one for the entity (with @Entity annotation) and the other with a DTO (with @JsonApiResource). This solution works but I'm looking for another easier solution to have my entities with the @JsonApiResource, because without the jpa module the annotation worked fine.

Did anyone get an idea on it ?

exports commented 7 years ago

@loickR Is your mapped entity approach works fine? I cannot create new resource when use mapped entity, and the validation module is broken, so I have to patch the whole module to make it work.

loickR commented 7 years ago

I think so but currently, I've three classes my entity User (with @Entity and @JsonApiResource), my repository and my JpaConfig class implementing the SpringTransactionRunner bean and the JpaModule (like the example on github). Here the code of my classes

@JsonApiResource(type = "users")
@Entity
@Table (name = "users")
@EqualsAndHashCode(of = "firstName")
@NoArgsConstructor
public class User {

    @Getter
    @Setter
    @JsonApiId
    @Id
    @GeneratedValue (strategy = GenerationType.AUTO)
    private Long id;

    @Getter
    @Setter
    @Column
    @JsonProperty (value = "last-name")
    private String lastName;

    @Getter
    @Setter
    @Column
    @JsonProperty (value = "first-name")
    private String firstName;
}
@Component
public class UserResourceRepository extends JpaEntityRepository<User, Long>  {

    @Autowired
    public UserResourceRepository(JpaModule module) {
        super(module, JpaRepositoryConfig.create(User.class));
    } 
}
@Configuration
public class JpaConfig {

    @Autowired
    private EntityManager em;

    @Autowired
    private TransactionRunner transactionRunner;

    @Bean
    public SpringTransactionRunner transactionRunner() {
        return new SpringTransactionRunner();
    }

    @Bean
    public JpaModule jpaModule() {
       final JpaModule module = JpaModule.newServerModule(em, transactionRunner);
       return module;
    }
}

My application.yml

katharsis:
  resourcePackage: com.my_package
  domainName: http://localhost:8080
  pathPrefix: /api
  jpa:
    enabled: false

spring:
  datasource:
    driverClassName: org.postgresql.Driver
    url: jdbc:postgresql://localhost:5432/my_db
    username: user
    password: user_pass
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
exports commented 7 years ago

I'm switching to mapped dto so I can modify the type now.

And btw, there is an undocumented KatharsisJpaAutoConfiguration in the latest version which will automatically discover and load all your entities as resources if no bean type of JpaModule present, so you can safely remove the jpaConfig and let the autoconfigure thing handle these stuff for you

remmeier commented 7 years ago

one could extend the JpaResourceInformationBuilder.getResourceType. Currently it already checks a (deprecated) "JpaResource" annotation. Maybe that one should be de-deprecated.

All of that is a bit historic due to the old resource lookup mechanism which is then has been refactored. Potentially one could also check for JsonApiResource. Which would be better.

loickR commented 7 years ago

Okay, thanks for the reply :). @exports Yes I already checked on it but I need to define manually my repositories in order to customize them for CRUD operations. @remmeier I don't understand how does JpaResourceInformationBuilder work and how can I use it ? My repositories must extends it or these my entities ? Anyway, I've seen the annotation what you meant "@JpaResource" it would be fine if a future support for that may be released (as you mention it, it's deprecated right now). For the moment, I check on split my entities and my dto classes and waiting for a stronger support between spring and katharsis.

remmeier commented 7 years ago

JpaResourceInformationBuilder is the thing taking care of parsing all the annotations. So more support in this area has to be implemented there. For know you can just use @JpaResource and we can either de-deprecate it or introduce a better solution.

loickR commented 7 years ago

Okay I got it, I've seen some tests using it and I'm going to see further. I don't really know if in a next feature you guys can make directly a such update with @JpaResource but thanks by the way for your explanation, katharsis is a good framework :) Maybe it can solve my problems with annotation because my url http://localhost:8080/users doesn't work and http://localhost:8080/user works at well.

LeRiton commented 7 years ago

Hi @remmeier , everyone,

I'm facing the same issue, trying to expose an entity to its pluralized form (or any other string provided by an annotation on this entity). As mentionned on the Gitter (may 02), @JsonApiResource is ignored when direct-exposing an entity, this left us with the deprecated (and buggy?) @JpaResource.

Without @JpaResource:

@Entity
public class Person {
}

is exposed at http://host:port/api-prefix/person.

But application crash at startup when adding @JpaResource to the entity:

Caused by: java.lang.UnsupportedOperationException: unknown type class com.sncf.igtl.re.katharsis.Person
    at io.katharsis.meta.MetaLookup.allocateMeta(MetaLookup.java:206) ~[katharsis-meta-3.0.1.jar:na]

After a little diggin', I suppose that when JpaResourceInformationBuilder try to build() resource information for a class and detect the annotation, it tries to retrieve meta using the JpaMetaLookup, which lacks a MetaJsonObject object provider (ResourceMetaProvider has one).

See https://github.com/katharsis-project/katharsis-framework/blob/f783c4a7532e07a31919f1770c135a6ab66a9e83/katharsis-jpa/src/main/java/io/katharsis/jpa/internal/JpaResourceInformationBuilder.java#L94-L102

Questions now!

Am I doing right? Is this a bug or misconfiguration? How can I provide custom resource type when exposing a JPA entity? DTO is one solution but left us with a lot of boilerplate code.

remmeier commented 7 years ago

So far changing the name has not really be attempted so I would consider it not being supported. But that can be changed (altough personally I prefer sticking to the naming of the entities, because it involves just more work without significant benefit).

I would need to the see entire exception. But we should wait a few days. There is a fairly substantial backlog when it comes to accepting PRs. On top of the PRs I have quite a large number of further improvements to katharsis-meta that I was not able to contribute. But @hibaymj is currently looking into the PRs.

LeRiton commented 7 years ago

Thanks for this answer.

But that can be changed (altough personally I prefer sticking to the naming of the entities, because it involves just more work without significant benefit).

I beg to differ. Java naming convention for entity class name is singular, and REST API often (despite the lack of specification or consensus for this specific topic) expose resources with plural form. JSON API examples use plural form URI, frameworks like Ember also expect /api/users instead of /api/user.

There is a fairly substantial backlog when it comes to accepting PRs. On top of the PRs I have quite a large number of further improvements to katharsis-meta that I was not able to contribute. But @hibaymj is currently looking into the PRs.

No rush here, I understand there is quite some work to do. Can you - or other maintainers - just tell us if this is planned to be supported?

I would need to the see entire exception.

There you are:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.5.3.RELEASE)

2017-05-05 10:39:48.816  INFO 3116 --- [           main] com.foo.katharsis.Application            : Starting Application on host with PID 3116 (D:\workspace\test-katharsis-spring\target\classes started by user in D:\workspace\test-katharsis-spring)
2017-05-05 10:39:48.820  INFO 3116 --- [           main] com.foo.katharsis.Application            : No active profile set, falling back to default profiles: default
2017-05-05 10:39:48.950  INFO 3116 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@279ad2e3: startup date [Fri May 05 10:39:48 CEST 2017]; root of context hierarchy
2017-05-05 10:39:52.449  INFO 3116 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2017-05-05 10:39:52.469  INFO 3116 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2017-05-05 10:39:52.471  INFO 3116 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.14
2017-05-05 10:39:52.684  INFO 3116 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2017-05-05 10:39:52.684  INFO 3116 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 3739 ms
2017-05-05 10:39:53.701  INFO 3116 --- [ost-startStop-1] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
2017-05-05 10:39:53.729  INFO 3116 --- [ost-startStop-1] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [
    name: default
    ...]
2017-05-05 10:39:53.867  INFO 3116 --- [ost-startStop-1] org.hibernate.Version                    : HHH000412: Hibernate Core {5.0.12.Final}
2017-05-05 10:39:53.869  INFO 3116 --- [ost-startStop-1] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
2017-05-05 10:39:53.871  INFO 3116 --- [ost-startStop-1] org.hibernate.cfg.Environment            : HHH000021: Bytecode provider name : javassist
2017-05-05 10:39:53.951  INFO 3116 --- [ost-startStop-1] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2017-05-05 10:39:54.292  INFO 3116 --- [ost-startStop-1] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
2017-05-05 10:39:54.970  INFO 3116 --- [ost-startStop-1] org.hibernate.tool.hbm2ddl.SchemaExport  : HHH000227: Running hbm2ddl schema export
2017-05-05 10:39:54.990  INFO 3116 --- [ost-startStop-1] org.hibernate.tool.hbm2ddl.SchemaExport  : HHH000230: Schema export complete
2017-05-05 10:39:55.063  INFO 3116 --- [ost-startStop-1] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2017-05-05 10:39:55.172 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : adding
2017-05-05 10:39:55.172 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : added
2017-05-05 10:39:55.173 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : allocate class com.foo.katharsis.Person
2017-05-05 10:39:55.229 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : add com.foo.katharsis.Person of type MetaEntity
2017-05-05 10:39:55.230 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : add com.foo.katharsis.Person.name of type MetaEntityAttribute
2017-05-05 10:39:55.230 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : add com.foo.katharsis.Person.id of type MetaEntityAttribute
2017-05-05 10:39:55.230 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : add com.foo.katharsis.Person.Person$primaryKey of type MetaPrimaryKey
2017-05-05 10:39:55.230 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : adding
2017-05-05 10:39:55.230 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : adding com.foo.katharsis.Person
2017-05-05 10:39:55.230 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : adding com.foo.katharsis.Person.name
2017-05-05 10:39:55.232 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : allocate class java.lang.String
2017-05-05 10:39:55.233 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : add base.string of type MetaPrimitiveType
2017-05-05 10:39:55.233 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : added com.foo.katharsis.Person.name
2017-05-05 10:39:55.234 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : adding com.foo.katharsis.Person.id
2017-05-05 10:39:55.234 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : allocate class java.lang.Long
2017-05-05 10:39:55.234 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : add base.long of type MetaPrimitiveType
2017-05-05 10:39:55.234 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : added com.foo.katharsis.Person.id
2017-05-05 10:39:55.234 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : adding com.foo.katharsis.Person.Person$primaryKey
2017-05-05 10:39:55.234 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : added com.foo.katharsis.Person.Person$primaryKey
2017-05-05 10:39:55.234 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : added com.foo.katharsis.Person
2017-05-05 10:39:55.234 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : adding base.string
2017-05-05 10:39:55.234 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : added base.string
2017-05-05 10:39:55.234 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : adding base.long
2017-05-05 10:39:55.235 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : added base.long
2017-05-05 10:39:55.235 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : added
2017-05-05 10:39:55.252 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : adding
2017-05-05 10:39:55.252 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : added
2017-05-05 10:39:55.252 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : adding
2017-05-05 10:39:55.252 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : added
2017-05-05 10:39:55.277 DEBUG 3116 --- [ost-startStop-1] io.katharsis.meta.MetaLookup             : allocate class com.foo.katharsis.Person
2017-05-05 10:39:55.278 ERROR 3116 --- [ost-startStop-1] o.s.b.c.embedded.tomcat.TomcatStarter    : Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name 'springBootSampleKatharsisFilter' defined in io.katharsis.spring.boot.v3.KatharsisConfigV3: Unsatisfied dependency expressed through method 'springBootSampleKatharsisFilter' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'katharsisBoot' defined in io.katharsis.spring.boot.v3.KatharsisConfigV3: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [io.katharsis.core.internal.boot.KatharsisBoot]: Factory method 'katharsisBoot' threw exception; nested exception is java.lang.UnsupportedOperationException: unknown type class com.foo.katharsis.Person
2017-05-05 10:39:55.314  WARN 3116 --- [           main] ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.boot.context.embedded.EmbeddedServletContainerException: Unable to start embedded Tomcat
2017-05-05 10:39:55.315  INFO 3116 --- [           main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2017-05-05 10:39:55.315  INFO 3116 --- [           main] org.hibernate.tool.hbm2ddl.SchemaExport  : HHH000227: Running hbm2ddl schema export
2017-05-05 10:39:55.323  INFO 3116 --- [           main] org.hibernate.tool.hbm2ddl.SchemaExport  : HHH000230: Schema export complete
2017-05-05 10:39:55.340 ERROR 3116 --- [           main] o.s.boot.SpringApplication               : Application startup failed

org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.boot.context.embedded.EmbeddedServletContainerException: Unable to start embedded Tomcat
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:137) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:536) ~[spring-context-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:737) [spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:370) [spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:314) [spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1162) [spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1151) [spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at com.foo.katharsis.Application.main(Application.java:13) [classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_91]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_91]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_91]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_91]
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147) [idea_rt.jar:na]
Caused by: org.springframework.boot.context.embedded.EmbeddedServletContainerException: Unable to start embedded Tomcat
    at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.initialize(TomcatEmbeddedServletContainer.java:123) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.<init>(TomcatEmbeddedServletContainer.java:84) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory.getTomcatEmbeddedServletContainer(TomcatEmbeddedServletContainerFactory.java:554) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory.getEmbeddedServletContainer(TomcatEmbeddedServletContainerFactory.java:179) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.createEmbeddedServletContainer(EmbeddedWebApplicationContext.java:164) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:134) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    ... 13 common frames omitted
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'springBootSampleKatharsisFilter' defined in io.katharsis.spring.boot.v3.KatharsisConfigV3: Unsatisfied dependency expressed through method 'springBootSampleKatharsisFilter' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'katharsisBoot' defined in io.katharsis.spring.boot.v3.KatharsisConfigV3: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [io.katharsis.core.internal.boot.KatharsisBoot]: Factory method 'katharsisBoot' threw exception; nested exception is java.lang.UnsupportedOperationException: unknown type class com.foo.katharsis.Person
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:749) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:467) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1173) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1067) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:234) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addAsRegistrationBean(ServletContextInitializerBeans.java:182) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addAsRegistrationBean(ServletContextInitializerBeans.java:177) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addAdaptableBeans(ServletContextInitializerBeans.java:159) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.springframework.boot.web.servlet.ServletContextInitializerBeans.<init>(ServletContextInitializerBeans.java:80) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.getServletContextInitializerBeans(EmbeddedWebApplicationContext.java:241) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.selfInitialize(EmbeddedWebApplicationContext.java:228) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.access$000(EmbeddedWebApplicationContext.java:89) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext$1.onStartup(EmbeddedWebApplicationContext.java:213) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.springframework.boot.context.embedded.tomcat.TomcatStarter.onStartup(TomcatStarter.java:55) ~[spring-boot-1.5.3.RELEASE.jar:1.5.3.RELEASE]
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5196) ~[tomcat-embed-core-8.5.14.jar:8.5.14]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) ~[tomcat-embed-core-8.5.14.jar:8.5.14]
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1419) ~[tomcat-embed-core-8.5.14.jar:8.5.14]
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409) ~[tomcat-embed-core-8.5.14.jar:8.5.14]
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_91]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[na:1.8.0_91]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) ~[na:1.8.0_91]
    at java.lang.Thread.run(Thread.java:745) ~[na:1.8.0_91]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'katharsisBoot' defined in io.katharsis.spring.boot.v3.KatharsisConfigV3: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [io.katharsis.core.internal.boot.KatharsisBoot]: Factory method 'katharsisBoot' threw exception; nested exception is java.lang.UnsupportedOperationException: unknown type class com.foo.katharsis.Person
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1173) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1067) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:835) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    ... 27 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [io.katharsis.core.internal.boot.KatharsisBoot]: Factory method 'katharsisBoot' threw exception; nested exception is java.lang.UnsupportedOperationException: unknown type class com.foo.katharsis.Person
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    ... 40 common frames omitted
Caused by: java.lang.UnsupportedOperationException: unknown type class com.foo.katharsis.Person
    at io.katharsis.meta.MetaLookup.allocateMeta(MetaLookup.java:206) ~[katharsis-meta-3.0.1.jar:na]
    at io.katharsis.meta.MetaLookup.getMetaInternal(MetaLookup.java:146) ~[katharsis-meta-3.0.1.jar:na]
    at io.katharsis.meta.MetaLookup.getMeta(MetaLookup.java:119) ~[katharsis-meta-3.0.1.jar:na]
    at io.katharsis.jpa.internal.JpaResourceInformationBuilder.build(JpaResourceInformationBuilder.java:97) ~[katharsis-jpa-3.0.1.jar:na]
    at io.katharsis.module.ModuleRegistry$CombinedResourceInformationBuilder.build(ModuleRegistry.java:310) ~[katharsis-core-3.0.1.jar:na]
    at io.katharsis.core.internal.repository.information.DefaultResourceRepositoryInformationBuilder.build(DefaultResourceRepositoryInformationBuilder.java:55) ~[katharsis-core-3.0.1.jar:na]
    at io.katharsis.core.internal.repository.information.DefaultResourceRepositoryInformationBuilder.build(DefaultResourceRepositoryInformationBuilder.java:44) ~[katharsis-core-3.0.1.jar:na]
    at io.katharsis.module.ModuleRegistry$CombinedRepositoryInformationBuilder.build(ModuleRegistry.java:360) ~[katharsis-core-3.0.1.jar:na]
    at io.katharsis.module.ModuleRegistry.applyRepositoryRegistration(ModuleRegistry.java:463) ~[katharsis-core-3.0.1.jar:na]
    at io.katharsis.module.ModuleRegistry.init(ModuleRegistry.java:426) ~[katharsis-core-3.0.1.jar:na]
    at io.katharsis.core.internal.boot.KatharsisBoot.bootDiscovery(KatharsisBoot.java:194) ~[katharsis-core-3.0.1.jar:na]
    at io.katharsis.core.internal.boot.KatharsisBoot.boot(KatharsisBoot.java:176) ~[katharsis-core-3.0.1.jar:na]
    at io.katharsis.spring.boot.v3.KatharsisConfigV3.katharsisBoot(KatharsisConfigV3.java:52) ~[katharsis-spring-3.0.1.jar:na]
    at io.katharsis.spring.boot.v3.KatharsisConfigV3$$EnhancerBySpringCGLIB$$a05f1399.CGLIB$katharsisBoot$4(<generated>) ~[katharsis-spring-3.0.1.jar:na]
    at io.katharsis.spring.boot.v3.KatharsisConfigV3$$EnhancerBySpringCGLIB$$a05f1399$$FastClassBySpringCGLIB$$2050ba9c.invoke(<generated>) ~[katharsis-spring-3.0.1.jar:na]
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) ~[spring-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:358) ~[spring-context-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at io.katharsis.spring.boot.v3.KatharsisConfigV3$$EnhancerBySpringCGLIB$$a05f1399.katharsisBoot(<generated>) ~[katharsis-spring-3.0.1.jar:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_91]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_91]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_91]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_91]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162) ~[spring-beans-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    ... 41 common frames omitted

Process finished with exit code 1

Codebase used for this test case:

application.properties

katharsis.jpa.enabled=true

Application.java

@SpringBootApplication
@Import({KatharsisConfigV3.class})
public class Application {
    public static void main(final String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Person.java

// Uncomment to unleash 'unknown type class com.foo.katharsis.Person'
// @JpaResource(type = "people")
@Entity @Getter @Setter
@NoArgsConstructor(access = AccessLevel.PACKAGE)
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
}
remmeier commented 7 years ago

yes, plural is nicer. JSON API says:

Note: This spec is agnostic about inflection rules, so the value of type can be either plural or singular. However, the same value should be used consistently throughout an implementation.

I consider myself just being too lazy for this kind of things and take the shortest route...

The maintance topics is currently being discussed. I'm not a maintainer and the past working mode was not really a working working mode.

Thx for the exception. I fixed it locally in my repository. It will find its way into the official one with all the other changes.

chb0github commented 7 years ago

This issue of plural and inflection came up several times. The pluralization needs to be at the controller level to make sense: If you think of this in HTTP terms, orginally, HTTP was basically a webified file system . So, if I had some documents I would naturally put them in a directory called /documents but each is a singular document so, if I did an ls /documents I would get:

doc1.doc
doc2.doc

So, Ideally you would POST a single document to documents. IN JSONApi, you declare the type when you post and in this case you would declare

{
    attributes: {
      type: 'document'
   }
}

However, the way katharsis is implemented, it is not possible to make the distinction between plural and singular in the correct cases. So, if you declare your JSONApi entity as document then when you post the payload looks good but you end up posting to a resource called document (no plural). If you make the resource plural to fix this then the payload type is plural.

There has been discussion of using an inflection library to bypass this and get smart about it (The one spring-data-rest uses is pretty good for english) but naturally the angry mob comes and says, in summary: "YOU HAVE TO SUPPORT MY LANGUAGE TOO! Vive la resistance!" - never mind the fact the the entire web is still english/ascii oriented.

At this point, I would support the use of an inflector and with entity declaration being singular and just limit it to English.

If you're interested, I can point you at the inflector in use and we can work on a PR

LeRiton commented 7 years ago

@remmeier could you tell me if recent version (3.0.3 ?) enable the @JpaResource(type = "people") usage?

Is there any consensus about plural form for JPA entity through direct mapping? Will @JpaResource stay deprecated?

Thanks!