Spring Data Rest - _links

匿名 (未验证) 提交于 2019-12-03 03:04:01

问题:

Edit 14/08/14 13:29

My next conclusion is that the hal+json format produced from my @RepositoryRestResource CrudRepository is incorrect.

The tutorial (http://spring.io/guides/gs/accessing-data-rest/) shows the output of a hypermedia Rest JPA entity as: (please note there is no "rel" element, and "links" is not an array)

{    "_links" : {        "people" : {            "href" : "http://localhost:8080/people{?page,size,sort}"        }    }  } 

However, the reference docs (http://docs.spring.io/spring-data/rest/docs/1.1.x/reference/html/intro-chapter.html) show that the output should be:

{     "links" : [ {         "rel" : "customer",         "href" : "http://localhost:8080/customer"       }, {          "rel" : "profile",          "href" : "http://localhost:8080/profile"       }  } 

Does anyone know why this is?

=====================================

Edit 14/08/14: I have taken my debugging a step further. By providing my own implementation of a org.springframework.hateoas.ResourceSupport class, which inspects the json for "_links" rather than "links" I get a step further. The error is:

"Can not deserialize instance of java.util.ArrayList out of START_OBJECT token ..... through reference chain: com.ebs.solas.admin.test.SolicitorDTO[\"_links\"]"

This is because the org.springframework.hateoas.ResourceSupport class seems to require that the links attribute be a json array. And by default the json+hal output produced by Spring Data for a Rest Entity does not produce an array (there are no square brackets):

"_links" : {   "self" : {     "href" : "http://localhost:9090/solas-admin-data-api/solicitorFirms/Fxxx"   },   "solicitors" : {     "href" : "http://localhost:9090/solas-admin-data-api/solicitorFirms/Fxxx/solicitor   } } 

Hopefully someone from the Spring forums could help me here.

==============================================

please see an outline of my Spring Data repository code:

@RepositoryRestResource     public interface SolicitorFirmRepository extends CrudRepository<SolicitorFirm, String> { }  @Entity @RestResource @Table(name="XXXX", schema = "XXX") public class SolicitorFirm implements Serializable { } 

This successfully generates the following hateoas resource:

{ "firmNumber" : "FXXXX", "solicitorType" : "r", "companyName" : "XXXX", "address1" : "XXXX", "address2" : "XXX", "address3" : "XXX", "address4" : null, "phoneNumber" : "XXXXX", "faxNumber" : "XXXXX", "county" : "OY", "_links" : {     "self" : {         "href" : "http://localhost:9090/solas-admin-data-api/solicitorFirms/XXXX"     },     "solicitors" : {         "href" : "http://localhost:9090/solas-admin-data-api/solicitorFirms/XXXX/solicitors"     }  } 

HOWEVER, when i define a DTO for clientside/controller use:

import org.springframework.hateoas.ResourceSupport; public class SolicitorFirmDTO extends ResourceSupport {    ..... } 

and use the following code

RestTemplate rt = new RestTemplate(); String uri = new String("//xxxxx:9090/solas-admin-data-api/solicitors/Sxxxxx"); SolicitorFirmDTO u = rt.getForObject(uri, SolicitorFirmDTO.class, "SXXXX"); 

I get the following error:

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "_links" (class com.ebs.solas.admin.test.SolicitorFirmDTO), not marked as ignorable (7 known properties: xx])

For some reason the json produced by Spring Data Rest adds the entity links under _links while the HATEOAS resource superclass expects links?

Can any one help? is this a version issue or do I need some extra configuration to map _links to links

I have tried MappingJackson2HttpMessageConverter and various media types application/json+hal to no avail.

回答1:

For Spring-boot 1.3.3 the method exchange() for List is working

public void test1() {      RestTemplate restTemplate = restTemplate();      ParameterizedTypeReference<PagedResources<User>> responseTypeRef = new ParameterizedTypeReference<PagedResources<User>>() {     };      String API_URL = "http://localhost:8080/api/v1/user"     ResponseEntity<PagedResources<User>> responseEntity = restTemplate.exchange(API_URL, HttpMethod.GET,             (HttpEntity<User>) null, responseTypeRef);      PagedResources<User> resources = responseEntity.getBody();     Collection<User> users = resources.getContent();     List<User> userList = new ArrayList<User>(users);      System.out.println(userList);  }  private RestTemplate restTemplate() {      ObjectMapper mapper = new ObjectMapper();     mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);     mapper.registerModule(new Jackson2HalModule());      MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();     converter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/hal+json"));     converter.setObjectMapper(mapper);      List<HttpMessageConverter<?>> converterList = new ArrayList<HttpMessageConverter<?>>();     converterList.add(converter);     RestTemplate restTemplate = new RestTemplate(converterList);      return restTemplate; } 


回答2:

Also with mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) use @JsonIgnoreProperties(ignoreUnknown = true) on every Entity:

@Entity @JsonIgnoreProperties(ignoreUnknown = true) public class User {     ...  } 


回答3:

thanks for your response.

In answer to your questions,

1) I believe that my input and output are both HAL. You will see from my original post that the json produced from my @RepositoryRestResource is HAL (notice it contains ref links to itself and associated entities):

{   "firmNumber" : "Fxx",   "solicitorType" : "r",   "companyName" : "xxx",   "address1" : "xxx,",   "address2" : "xx,",   "address3" : "xxx,",   "_links" : {       "self" : {          "href" : "http://localhost:9090/solas-admin-data-api/solicitorFirms/Fxx"       },       "solicitors" : {          "href" : "http://localhost:9090/solas-admin-data-api/solicitorFirms/Fxx/solicitors      }   } } 

However the reference links are under the attribute name "_links", but the RestSupport class on the client side does not seem to expect any _underscore, it only seems to search for "links"

2) yes i have specified @EnableHypermediaSupport(type = HypermediaType.HAL),

please see below for my full configuration is as follows (javaconfig):

@Configuration @ComponentScan("com.ebs.solas.admin") @EnableJpaRepositories("com.ebs.solas.admin") @EnableTransactionManagement @Import(RepositoryRestMvcConfiguration.class) class ApplicationConfig {      @Bean     public DataSource dataSource() {            DriverManagerDataSource dataSource = new DriverManagerDataSource();           dataSource.setDriverClassName("com.ibm.db2.jcc.DB2Driver");           dataSource.setUrl("jdbc:db2://xxxx:52001/xxxx");           dataSource.setUsername( "xxx" );           dataSource.setPassword( "xxx" );           return dataSource;     }      @Bean     public LocalContainerEntityManagerFactoryBean entityManagerFactory() {         HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();         vendorAdapter.setDatabase(Database.DB2);         vendorAdapter.setGenerateDdl(false);         LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();         factory.setJpaVendorAdapter(vendorAdapter);         factory.setPackagesToScan("com.ebs.solas.admin");         factory.setDataSource(dataSource());         return factory;     }      @Bean     public PlatformTransactionManager transactionManager() {         JpaTransactionManager txManager = new JpaTransactionManager();         txManager.setEntityManagerFactory(entityManagerFactory().getObject());         return txManager;     } }   public class RestWebApplicationInitializer implements WebApplicationInitializer {       public void onStartup(ServletContext context) throws ServletException {         AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();         rootContext.register(ApplicationConfig.class);          context.addListener(new ContextLoaderListener(rootContext));          RepositoryRestDispatcherServlet exporter = new RepositoryRestDispatcherServlet();         ServletRegistration.Dynamic reg = context.addServlet("exporter", exporter);         reg.setLoadOnStartup(1);         reg.addMapping("/*");     } }   @Configuration @ComponentScan("com.ebs.solas.admin") @EnableWebMvc @EnableHypermediaSupport(type = HypermediaType.HAL) class WebMVCConfiguration extends WebMvcConfigurationSupport {      @Override     public void configureContentNegotiation(ContentNegotiationConfigurer c) {         c.defaultContentType(MediaType.APPLICATION_JSON);     }      @Bean     public MultipartResolver multipartResolver() {          return new StandardServletMultipartResolver();     } } 

My RestController also specifies that the RestTemplate should use hal+json message conversion format, see below

@RestController public class TestController {       @RequestMapping(value="/test", method=RequestMethod.GET, produces={"application/hal+json"})      @ResponseStatus(HttpStatus.OK)      public SolicitorDTO doTest() {         ObjectMapper mapper = new ObjectMapper();         mapper.registerModule(new Jackson2HalModule());          MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();          converter.setSupportedMediaTypes(org.springframework.http.MediaType.parseMediaTypes("application/hal+json"));         converter.setObjectMapper(mapper);          RestTemplate rt = new RestTemplate();         rt.getMessageConverters().add(converter);           String uri = new String("http://localhost:9090/solas-admin-data-api/solicitors/{id}");         SolicitorDTO u = rt.getForObject(uri, SolicitorDTO.class, "Sxxxxx");         return u;      }    } 

Thanks for your help, appdJava



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!