Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inheritance of entities/repositories [DATAREST-344] #726

Open
spring-projects-issues opened this issue Jul 1, 2014 · 10 comments
Open

Inheritance of entities/repositories [DATAREST-344] #726

spring-projects-issues opened this issue Jul 1, 2014 · 10 comments
Assignees
Labels
in: repository status: feedback-provided Feedback has been provided type: bug A general bug

Comments

@spring-projects-issues
Copy link

Benjamin M opened DATAREST-344 and commented

I'd like to use inheritance for my entities. And the only way of getting it kinda working was to do the following:

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="type")
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="type")
public abstract class Message implements Identifiable<UUID> { ... }

@Entity
@DiscriminatorValue("TEXT")
@JsonTypeName("TEXT")
public class TextMessage extends Message { ... }

@Entity
@DiscriminatorValue("TODO")
@JsonTypeName("TODO")
public class TodoMessage extends Message { ... }

public interface MessageRepo extends JpaRepository<Message, UUID> { }

public interface TextMessageRepo extends JpaRepository<TextMessage, UUID> { }

public interface TodoMessageRepo extends JpaRepository<TodoMessage, UUID> { }

When I now call GET http://localhost:8080/webapp/messages I get the following output:

{
  "_links": {
    "self": { "href": "http://localhost:8080/webapp/messages{?page,size,sort}", "templated": true }
  },
  "_embedded": {
    "textMessages": [
      { ... },
      { ... }
    ],
    "todoMessages": [
      { ... }
    ]
  },
  "page": {
    "size": 20, "totalElements": 3, "totalPages": 1, "number": 0
  }
}

As you can see, there's textMessages and todoMessages within the _embedded object. So, I cannot really sort my messages.

Is there a way to get all my messages within a single array?

EDIT: I tried to get rid of my additional projections, but that won't work:
If I only have a @Projection for Message.class, it won't get applied when calling GET http://localhost:8080/webapp/messages?projection=summary,
BUT it does work, if it's an inherited projection: GET http://localhost:8080/webapp/messageInboxes/89cb89db-67c5-49b3-8f1f-00b63b74ca4a?projection=summary
with:

@Projection(name = "summary", types = MessageInbox.class)
public interface MessageInboxSummary {
	MessageSummary getMessage();
}

@Projection(name = "summary", types = Message.class)
public interface MessageSummary {
	String getSubject();
}

@Entity
public class MessageInbox extends Identifiable<UUID> {
	@ManyToOne
	@JoinColumn(name = "Message_id", nullable = false, updatable = false)
	Message message;
	public Message getMessage() { return message; }
}

EDIT 2:
I now somehow fixed it / encountered a new bug...

If I put

@RepositoryRestResource(collectionResourceRel="messages", path="messages")

on all 3 repositories it behaves like I want it to: Every kind of message is available under GET http://localhost:8080/webapp/messages and all get displayed within the same array!

But now there are 2 issues:

  1. The index page displays:
{
  "_links": {
    "messages": [
      {
        "href": "http://localhost:8080/webapp/messages{?page,size,sort,projection}",
        "templated": true
      },
      {
        "href": "http://localhost:8080/webapp/messages{?page,size,sort,projection}",
        "templated": true
      },
      {
        "href": "http://localhost:8080/webapp/messages{?page,size,sort,projection}",
        "templated": true
      }
    ]
  }
}
  1. if I add itemResourceRel="message" to the @RepositoryRestResource annotation on all 3 repositories, the URL GET http://localhost:8080/webapp/messages will display randomly either the TextMessages OR the TodoMessages , but never both

Affects: 2.1.1 (Dijkstra SR1)

9 votes, 16 watchers

@spring-projects-issues
Copy link
Author

Oliver Drotbohm commented

I think falling back to a repo per concrete type is not a good idea. You shouldn't need to tweak your repository setup that much to get the output you want.

Have you tried registering a RelProvider implementation that returns message/messages for all subtypes of Message?

@spring-projects-issues
Copy link
Author

Benjamin M commented

There's one situation when fallback would be pretty awesome:

Basically I did only want to use a single repository for all 3 entities:

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="type")
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="type")
public abstract class Message implements Identifiable<UUID> {
	@Column(name = "type", insertable = false, updatable = false)
	String type;
	public String getType() { return type; }
	public void setType(String type) { this.type = type; }
}
 
@Entity
@DiscriminatorValue("TEXT")
@JsonTypeName("TEXT")
public class TextMessage extends Message { ... }
 
@Entity
@DiscriminatorValue("TODO")
@JsonTypeName("TODO")
public class TodoMessage extends Message { ... }
 
public interface MessageRepo extends JpaRepository<Message, UUID> { }

Jackson handles this pretty well, because I have:

@Configuration
public class RepositoryRestMvcConfig extends RepositoryRestMvcConfiguration {
	@Override
	protected void configureJacksonObjectMapper(ObjectMapper objectMapper) {
		ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
		provider.addIncludeFilter(new AnnotationTypeFilter(JsonTypeName.class));
		for(BeanDefinition candidate : provider.findCandidateComponents(Application.class.getPackage().getName())) {
			objectMapper.registerSubtypes(ClassUtils.resolveClassName(candidate.getBeanClassName(), ClassUtils.getDefaultClassLoader()));
		}
	}
}

(Maybe this would be a nice default for RepositoryRestMvcConfiguration ?)

So I can do:

GET http://localhost:8080/webapp/messages
{
  "_links": { ... },
  "_embedded": {
    "messages": [
      {
        "type": "TEXT",
        "_links": {
          "self": {
            "href": "http://localhost:8080/webapp/messages/b58a57bd-eb63-49e6-94c9-8ea92ffa193d{?projection}",
            "templated": true
          }
        }
      },
      {
        "type": "TODO",
        "_links": {
          "self": {
            "href": "http://localhost:8080/webapp/messages/f50c48ee-3e40-462c-a2c2-49add268ead0{?projection}",
            "templated": true
          }
        }
      }
    ]
  },
  "page": { ... }
}

POST http://localhost:8080/webapp/messages
{
  "type":"TEXT"
}

POSTing data this way, inserts it into the database, but the HTTP response fails for the same reason as the GET request:

2014-07-02 12:06:19,599 ERROR o.s.d.rest.webmvc.AbstractRepositoryRestController: 171 - Cannot create self link for class TextMessage! No persistent entity found!
java.lang.IllegalArgumentException: Cannot create self link for class TextMessage! No persistent entity found!
	at org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler.getSelfLinkFor(PersistentEntityResourceAssembler.java:81) ~[PersistentEntityResourceAssembler.class:na]
	at org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler.toResource(PersistentEntityResourceAssembler.java:64) ~[PersistentEntityResourceAssembler.class:na]
	at org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler.toResource(PersistentEntityResourceAssembler.java:32) ~[PersistentEntityResourceAssembler.class:na]
	at org.springframework.data.web.PagedResourcesAssembler.createResource(PagedResourcesAssembler.java:144) ~[PagedResourcesAssembler.class:na]
	at org.springframework.data.web.PagedResourcesAssembler.toResource(PagedResourcesAssembler.java:96) ~[PagedResourcesAssembler.class:na]
	at org.springframework.data.rest.webmvc.AbstractRepositoryRestController.entitiesToResources(AbstractRepositoryRestController.java:214) ~[AbstractRepositoryRestController.class:na]
	at org.springframework.data.rest.webmvc.AbstractRepositoryRestController.resultToResources(AbstractRepositoryRestController.java:201) ~[AbstractRepositoryRestController.class:na]
	at org.springframework.data.rest.webmvc.RepositoryEntityController.getCollectionResource(RepositoryEntityController.java:168) ~[RepositoryEntityController.class:na]

Now I'll try to find out, how this RelProvider stuff you mentioned works and where to register it. I'll give feedback later.

EDIT: Now figured out how to write my own RelProvider (which was as easy as possible):

new RelProvider() {
	@Override public boolean supports(Class<?> arg0) {
		return arg0.isAssignableFrom(Message.class);
	}
			
	@Override public String getItemResourceRelFor(Class<?> type) {
		return "message";
	}
		
	@Override public String getCollectionResourceRelFor(Class<?> type) {
		return "messages";
	}
};

But I don't know how/where to register it. Inside RepositoryRestMvcConfiguration you have @Autowired(required = false) RelProvider relProvider which seems to be an instance of DelegatingRelProvider. The only way to add a RelProvider there, is to use the constructor. But when I use Open call Hierarchy in Eclipse, it finds nothing!

Search goes on...

Here ( https://github.com/spring-projects/spring-hateoas ) it's said "automatically picks up all RelProvider implementations in the ApplicationContext and bundles them into a DelegatingRelProvider available for autowiring."

@EnableHypermediaSupport is enabled, because I use Spring Boot with @Import(RepositoryRestMvcConfig.class) (I only customized the Jackson thing stated above).

I did the following:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MessageRelProvider implements RelProvider {
	@Override public boolean supports(Class<?> arg0) {
		return arg0.isAssignableFrom(Message.class);
	}
	@Override public String getItemResourceRelFor(Class<?> type) {
		return "message";
	}
	@Override public String getCollectionResourceRelFor(Class<?> type) {
		return "messages";
	}
}

But when I call GET http://localhost:8080/webapp/messages, it still has "_embedded": {
"textMessages": [... instead of "_embedded": {
"messages": [...

@spring-projects-issues
Copy link
Author

Pablo Santiago commented

Just adding my 2 cents here:

arg0.isAssignableFrom(Message.class)

Was returning false for me. I changed it to:

org.apache.commons.lang3.ClassUtils.isAssignable(arg0, Message.class);

And now I get the correct information

@spring-projects-issues
Copy link
Author

Manuel Sousa commented

I used the above suggestion and it fixed the _embedded so that it would show all subclasses.

However in the _links it still uses the subclassname instead of the value returned by getItemResourceRelFor. Did this also happen for you / did you manage to fix it?

In my case this is breaking access from the hateoas links so I needed to create one repository for each subclass again, still better than nothing being able to access by the superclass

@spring-projects-issues
Copy link
Author

David Riccitelli commented

I was able to solve setting the path on the subclass repositories, e.g:

@RepositoryRestResource(exported = false, path = "messages")
public interface TextMessageRepo extends JpaRepository<TextMessage, UUID> { }
 (...)

@spring-projects-issues
Copy link
Author

Firoz Fazil commented

A dirty fix. In the above example make the subclass repository private so that the names can be changed to the parents and the endpoints will still be exposed by the repository of the parent.

@RepositoryRestResource(exported = false, path = "messages")
interface TextMessageRepo extends JpaRepository<TextMessage, UUID> { 
}

@spring-projects-issues
Copy link
Author

Mathias Ewald commented

I just tried that (using the RelProvider above and non-exported Repo suggested just before my comment here) and I am seeing some strange behavior. 

 

  1. I start the application and it all looks good: 

 

 .   ____          _            __ _ _ /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\___)| |_)| | | | | || (_| |  ) ) ) )  '  |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot ::        (v2.1.4.RELEASE)
2019-04-28 12:45:04.733  INFO 42556 --- [           main] c.e.s.SdrInheritanceApplication          : Starting SdrInheritanceApplication on mewald.local with PID 42556 (/Users/mewald/Downloads/sdr-inheritance/target/classes started by mewald in /Users/mewald/Downloads/sdr-inheritance)2019-04-28 12:45:04.735  INFO 42556 --- [           main] c.e.s.SdrInheritanceApplication          : No active profile set, falling back to default profiles: default2019-04-28 12:45:05.264  INFO 42556 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.2019-04-28 12:45:05.308  INFO 42556 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 39ms. Found 3 repository interfaces.2019-04-28 12:45:05.553  INFO 42556 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$3dae109f] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)2019-04-28 12:45:05.567  INFO 42556 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.hateoas.config.HateoasConfiguration' of type [org.springframework.hateoas.config.HateoasConfiguration$$EnhancerBySpringCGLIB$$bd2e5dd1] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)2019-04-28 12:45:05.829  INFO 42556 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)2019-04-28 12:45:05.846  INFO 42556 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]2019-04-28 12:45:05.846  INFO 42556 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.17]2019-04-28 12:45:05.905  INFO 42556 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext2019-04-28 12:45:05.906  INFO 42556 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1139 ms2019-04-28 12:45:06.061  INFO 42556 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...2019-04-28 12:45:06.124  INFO 42556 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.2019-04-28 12:45:06.166  INFO 42556 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [ name: default ...]2019-04-28 12:45:06.290  INFO 42556 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {5.3.9.Final}2019-04-28 12:45:06.290  INFO 42556 --- [           main] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found2019-04-28 12:45:06.360  INFO 42556 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.4.Final}2019-04-28 12:45:06.432  INFO 42556 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect2019-04-28 12:45:06.496  WARN 42556 --- [           main] org.hibernate.cfg.AnnotationBinder       : HHH000457: Joined inheritance hierarchy [com.example.sdrinheritance.Feedback] defined explicit @DiscriminatorColumnLegacy Hibernate behavior was to ignore the @DiscriminatorColumnHowever, as part of issue HHH-6911 we now apply the explicit @DiscriminatorColumnIf you would prefer the legacy behavior, enable the `hibernate.discriminator.ignore_explicit_for_joined` setting (hibernate.discriminator.ignore_explicit_for_joined=true)2019-04-28 12:45:06.810  INFO 42556 --- [           main] o.h.t.schema.internal.SchemaCreatorImpl  : HHH000476: Executing import script 'org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl@11ede87f'2019-04-28 12:45:06.812  INFO 42556 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'2019-04-28 12:45:07.492  INFO 42556 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'2019-04-28 12:45:07.521  WARN 42556 --- [           main] aWebConfiguration$JpaWebMvcConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning2019-04-28 12:45:07.784  INFO 42556 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''2019-04-28 12:45:07.787  INFO 42556 --- [           main] c.e.s.SdrInheritanceApplication          : Started SdrInheritanceApplication in 3.296 seconds (JVM running for 3.835)2019-04-28 12:45:07.816  INFO 42556 --- [           main] com.example.sdrinheritance.DataLoader    : Feedbacks saved

 

 

  1. I curl the root of the application and it still looks good:

 

$ curl http://localhost:8080
{
 "_links" : {
 "feedbacks" : {
 "href" : "http://localhost:8080/feedbacks"
 },
 "profile" : {
 "href" : "http://localhost:8080/profile"
 }
 }
}

 

  1. I curl the feedbacks endpoint I would expect to see one instance of "Feedback" but I get this:

 

curl -v http://localhost:8080/feedbacks
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /feedbacks HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 404
< Content-Type: application/hal+json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Sun, 28 Apr 2019 10:47:17 GMT
<
* Connection #0 to host localhost left intact
{"timestamp":"2019-04-28T10:47:17.196+0000","status":404,"error":"Not Found","message":"No message available","path":"/feedbacks"}

 

These are the logs I can see switching to DEBUG mode:

 

[2m2019-04-28 12:49:16.599[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[l-1 housekeeper][0;39m [36mcom.zaxxer.hikari.pool.HikariPool       [0;39m [2m:[0;39m HikariPool-1 - Pool stats (total=10, active=0, idle=10, waiting=0)
[2m2019-04-28 12:49:16.607[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[8080-Acceptor-0][0;39m [36mo.apache.tomcat.util.threads.LimitLatch [0;39m [2m:[0;39m Counting up[http-nio-8080-Acceptor-0] latch=1
[2m2019-04-28 12:49:16.608[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.a.tomcat.util.net.SocketWrapperBase   [0;39m [2m:[0;39m Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@3de12d42:org.apache.tomcat.util.net.NioChannel@1ad6e3b1:java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:8080 remote=/0:0:0:0:0:0:0:1:52893]], Read from buffer: [0]
[2m2019-04-28 12:49:16.608[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36morg.apache.tomcat.util.net.NioEndpoint  [0;39m [2m:[0;39m Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@3de12d42:org.apache.tomcat.util.net.NioChannel@1ad6e3b1:java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:8080 remote=/0:0:0:0:0:0:0:1:52893]], Read direct from socket: [87]
[2m2019-04-28 12:49:16.608[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.a.coyote.http11.Http11InputBuffer     [0;39m [2m:[0;39m Received [GET /feedbacks HTTP/1.1
Host: localhost:8080
User-Agent: curl/7.54.0
Accept: */*


]
[2m2019-04-28 12:49:16.609[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.a.c.authenticator.AuthenticatorBase   [0;39m [2m:[0;39m Security checking request GET /feedbacks
[2m2019-04-28 12:49:16.609[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36morg.apache.catalina.realm.RealmBase     [0;39m [2m:[0;39m   No applicable constraints defined
[2m2019-04-28 12:49:16.609[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.a.c.authenticator.AuthenticatorBase   [0;39m [2m:[0;39m  Not subject to any constraint
[2m2019-04-28 12:49:16.609[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36morg.apache.tomcat.util.http.Parameters  [0;39m [2m:[0;39m Set encoding to UTF-8
[2m2019-04-28 12:49:16.610[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.s.web.servlet.DispatcherServlet       [0;39m [2m:[0;39m GET "/feedbacks", parameters={}
[2m2019-04-28 12:49:16.614[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.s.w.s.handler.SimpleUrlHandlerMapping [0;39m [2m:[0;39m Mapped to ResourceHttpRequestHandler ["classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/", "/"]
[2m2019-04-28 12:49:16.614[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.j.s.OpenEntityManagerInViewInterceptor[0;39m [2m:[0;39m Opening JPA EntityManager in OpenEntityManagerInViewInterceptor
[2m2019-04-28 12:49:16.616[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.s.w.s.r.ResourceHttpRequestHandler    [0;39m [2m:[0;39m Resource not found
[2m2019-04-28 12:49:16.616[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.j.s.OpenEntityManagerInViewInterceptor[0;39m [2m:[0;39m Closing JPA EntityManager in OpenEntityManagerInViewInterceptor
[2m2019-04-28 12:49:16.616[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.s.web.servlet.DispatcherServlet       [0;39m [2m:[0;39m Completed 404 NOT_FOUND
[2m2019-04-28 12:49:16.616[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.a.c.c.C.[Tomcat].[localhost]          [0;39m [2m:[0;39m Processing ErrorPage[errorCode=0, location=/error]
[2m2019-04-28 12:49:16.619[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.s.web.servlet.DispatcherServlet       [0;39m [2m:[0;39m "ERROR" dispatch for GET "/error", parameters={}
[2m2019-04-28 12:49:16.620[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36ms.w.s.m.m.a.RequestMappingHandlerMapping[0;39m [2m:[0;39m Mapped to public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
[2m2019-04-28 12:49:16.620[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.j.s.OpenEntityManagerInViewInterceptor[0;39m [2m:[0;39m Opening JPA EntityManager in OpenEntityManagerInViewInterceptor
[2m2019-04-28 12:49:16.625[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.s.w.s.m.m.a.HttpEntityMethodProcessor [0;39m [2m:[0;39m Using 'application/hal+json', given [*/*] and supported [application/hal+json]
[2m2019-04-28 12:49:16.627[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.s.w.s.m.m.a.HttpEntityMethodProcessor [0;39m [2m:[0;39m Writing [{timestamp=Sun Apr 28 12:49:16 CEST 2019, status=404, error=Not Found, message=No message available, (truncated)...]
[2m2019-04-28 12:49:16.641[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.j.s.OpenEntityManagerInViewInterceptor[0;39m [2m:[0;39m Closing JPA EntityManager in OpenEntityManagerInViewInterceptor
[2m2019-04-28 12:49:16.641[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.s.web.servlet.DispatcherServlet       [0;39m [2m:[0;39m Exiting from "ERROR" dispatch, status 404
[2m2019-04-28 12:49:16.643[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.a.c.c.C.[.[.[/].[dispatcherServlet]   [0;39m [2m:[0;39m  Disabling the response for further output
[2m2019-04-28 12:49:16.644[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.a.tomcat.util.net.SocketWrapperBase   [0;39m [2m:[0;39m Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@3de12d42:org.apache.tomcat.util.net.NioChannel@1ad6e3b1:java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:8080 remote=/0:0:0:0:0:0:0:1:52893]], Read from buffer: [0]
[2m2019-04-28 12:49:16.646[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.apache.coyote.http11.Http11Processor  [0;39m [2m:[0;39m Error parsing HTTP request header


java.io.EOFException: null
	at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1206) ~[tomcat-embed-core-9.0.17.jar:9.0.17]
	at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.read(NioEndpoint.java:1140) ~[tomcat-embed-core-9.0.17.jar:9.0.17]
	at org.apache.coyote.http11.Http11InputBuffer.fill(Http11InputBuffer.java:731) ~[tomcat-embed-core-9.0.17.jar:9.0.17]
	at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:352) ~[tomcat-embed-core-9.0.17.jar:9.0.17]
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:294) ~[tomcat-embed-core-9.0.17.jar:9.0.17]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-9.0.17.jar:9.0.17]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) [tomcat-embed-core-9.0.17.jar:9.0.17]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) [tomcat-embed-core-9.0.17.jar:9.0.17]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.17.jar:9.0.17]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_181]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_181]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.17.jar:9.0.17]
	at java.lang.Thread.run(Thread.java:748) [na:1.8.0_181]


[2m2019-04-28 12:49:16.646[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.apache.coyote.http11.Http11Processor  [0;39m [2m:[0;39m Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@3de12d42:org.apache.tomcat.util.net.NioChannel@1ad6e3b1:java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:8080 remote=/0:0:0:0:0:0:0:1:52893]], Status in: [OPEN_READ], State out: [CLOSED]
[2m2019-04-28 12:49:16.648[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36mo.apache.tomcat.util.threads.LimitLatch [0;39m [2m:[0;39m Counting down[http-nio-8080-exec-2] latch=1
[2m2019-04-28 12:49:16.648[0;39m [32mDEBUG[0;39m [35m42736[0;39m [2m---[0;39m [2m[nio-8080-exec-2][0;39m [36morg.apache.tomcat.util.net.NioEndpoint  [0;39m [2m:[0;39m Socket: [org.apache.tomcat.util.net.NioChannel@1ad6e3b1:java.nio.channels.SocketChannel[closed]] closed

 

I made this demo code public here for easier reference: https://github.com/mathias-ewald/sdr-inheritance

Did this work for anyone?

 

 

 

 

@spring-projects-issues spring-projects-issues added status: waiting-for-feedback We need additional information before we can continue type: bug A general bug in: repository labels Dec 31, 2020
@spring-projects-issues
Copy link
Author

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

@spring-projects-issues spring-projects-issues added the status: feedback-reminder We've sent a reminder that we need additional information before we can continue label Jan 7, 2021
@gregturn gregturn added status: feedback-provided Feedback has been provided and removed status: feedback-reminder We've sent a reminder that we need additional information before we can continue status: waiting-for-feedback We need additional information before we can continue labels Jan 11, 2021
@flaviut
Copy link

flaviut commented Jan 28, 2024

It seems like RelProvider has been renamed to LinkRelationProvider: https://docs.spring.io/spring-hateoas/docs/current/api/org/springframework/hateoas/server/LinkRelationProvider.html

@flaviut
Copy link

flaviut commented Jan 28, 2024

Adding a new, exported=false repo in my case leads to 404 errors, since I have a repo at the same path that I do want to access.

However, digging into this a bit more, the logic to calculate the name in the links array is here, and this provides a hint:

this.path = Lazy.of(() -> annotation.map(RestResource::path) //
.map(String::trim) //
.filter(StringUtils::hasText) //
.orElseGet(() -> getDefaultPathFor(type)))//
.map(Path::new);

We can also chose our path segment by annotating the JPA Entity with @RestResource, without needing to create a new Repository interface. So the workaround that works for me is:

@Entity
@DiscriminatorValue("TEXT")
@JsonTypeName("TEXT")
+@RestResource(rel = "message", path = "messages")
public class TextMessage extends Message { ... }

@Entity
@DiscriminatorValue("TODO")
@JsonTypeName("TODO")
+@RestResource(rel = "message", path = "messages")
public class TodoMessage extends Message { ... }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: repository status: feedback-provided Feedback has been provided type: bug A general bug
Projects
None yet
Development

No branches or pull requests

4 participants