web-dev-qa-db-fra.com

Désactiver le langage d'application hypertexte (HAL) dans JSON?

Utilisation de Spring Data REST avec JPA dans la version 2.0.2.RELEASE.

Comment puis-je désactiver le langage d'application hypertexte (HAL) dans le JSON? http://stateless.co/hal_specification.html

J'ai déjà essayé beaucoup de choses, mais en vain. Par exemple, j'ai défini les en-têtes Accept et Content-type sur "application/json" au lieu de "application/hal + json" mais je reçois toujours le contenu JSON avec des hyperliens.

Par exemple, j'aimerais obtenir quelque chose comme:

{
"name" : "Foo",
"street" : "street Bar",
"streetNumber" : 2,
"streetLetter" : "b",
"postCode" : "D-1253",
"town" : "Munchen",
"country" : "Germany",
"phone" : "+34 4410122000",
"vat" : "000000001",
"employees" : 225,
"sector" : {
     "description" : "Marketing",
     "average profit": 545656665,
     "average employees": 75,
     "average profit per employee": 4556
     }
}

Au lieu de:

{
"name" : "Foo",
"street" : "street Bar",
"streetNumber" : 2,
"streetLetter" : "b",
"postCode" : "D-1253",
"town" : "Munchen",
"country" : "Germany",
"phone" : "+34 4410122000",
"vat" : "000000001",
"employees" : 225,
"_links" : {
     "self" : {
          "href" : "http://localhost:8080/app/companies/1"
     },
     "sector" : {
          "href" : "http://localhost:8080/app/companies/1/sector"
     }
}
}

Merci de votre aide.

37
jplandrain

(Hyper) types de média

Les paramètres par défaut de Spring Data REST utilisent HAL comme format de représentation hypermédia par défaut, donc le serveur renverra les éléments suivants pour les en-têtes Accept donnés:

  • Pas d'en-tête -> application/hal+json -> HAL
  • application/hal+json -> application/hal+json -> HAL
  • application/json -> application/json -> HAL (c'est ce que la configuration par défaut)
  • application/x-spring-data-verbose+json -> application/x-spring-data-verbose+json -> un format spécifique aux données Spring (en utilisant links pour le conteneur de liens et content comme wrapper pour les éléments de la collection.

Si vous configurez RepositoryRestConfiguration.setDefaultMediaType(…) dans un format non HAL, le serveur renverra le format JSON spécifique de Spring Data, sauf si vous demandez explicitement application/hal+json. Certes, l'option de configuration est probablement un peu trompeuse, j'ai donc déposé DATAREST-294 pour améliorer cela. Le problème a été résolu dans 2.1 RC1 (Dijkstra) 2014.

Notez que nous avons effectivement besoin d'un format hypermédia pour pouvoir exprimer les relations entre les ressources gérées et permettre la découverte du serveur. Il n'y a donc aucun moyen que vous puissiez vous en débarrasser complètement. Cela est principalement dû au fait que vous pouvez facilement planter le serveur si vous exposez des entités qui ont des relations bidirectionnelles ou si vous créez un énorme graphique d'objet.

Intégration d'entités liées

Si vous ne voulez jamais avoir de secteurs liés à et toujours en ligne, une option consiste simplement à exclure le SectorRepository de l’exportation en tant que ressource REST en premier lieu. Vous pouvez Pour ce faire, annotez l'interface du référentiel avec @RepositoryRestResource(exported = false).

Pour obtenir une représentation retournée comme vous l'avez publié dans votre exemple inférieur, jetez un œil à la fonctionnalité projections introduite dans Spring Data REST 2.1 M1. Elle vous permet essentiellement de créer en option vues sur une ressource qui peut différer de celle par défaut via une interface simple.

Vous définiriez essentiellement une interface:

@Projection(name = "foo", types = YourDomainClass.class)
interface Inlined {

  // list all other properties

  Sector getSector();
}

Si vous placez cette interface dans un (sous) package de votre classe de domaine ou l'enregistrez manuellement via RepositoryRestConfiguration.projectionConfiguration() les ressources exposant YourDomainClass accepteront un paramètre de requête projection afin que passer foo dans cet exemple rendrait la représentation en ligne comme vous le souhaitez.

Ce commit a plus d'informations sur la fonctionnalité en général, ce commit a un exemple de projection défini.

36
Oliver Drotbohm

Vous voulez donc 2 choses:

1) se débarrasser de _links champ
2) inclure le champ sector associé

Solution possible (fonctionne pour moi: D)

1) se débarrasser de _links
Pour cela, créez la classe ci-dessous:

[... package declaration, imports ...]
public class MyRepositoryRestMvcConfiguration extends RepositoryRestMvcConfiguration {
    public MyRepositoryRestMvcConfiguration(ApplicationContext context, ObjectFactory<ConversionService> conversionService) {
        super(context, conversionService);
    }

    @Bean
    protected LinkCollector linkCollector() {
        return new LinkCollector(persistentEntities(), selfLinkProvider(), associationLinks()) {
            public Links getLinksFor(Object object, List<Link> existingLinks) {
                return new Links();
            }
        };
    }
}

et l'utiliser par exemple:

[... package declaration, imports ...]
@SpringBootApplication
@Import({MyRepositoryRestMvcConfiguration.class})
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

Je suis sûr (99%, mais non testé) que vous n'aurez pas besoin de cette classe pour supprimer le _links pour l'entité/les entités associées inclus la façon dont le point suivant (2) est affiché.

2) inclure le champ sector associé
Pour cela, vous pouvez utiliser extraits (spécialement conçu pour ce scénario). Parce que l'exemple de Spring est si éloquent et qu'il est idiot de le copier ici, je vais juste le pointer: https://docs.spring.io/spring-data/rest/docs/3.1.x/reference/ html/# projections-excerpts.excerpting-common-access-data .
Mais juste pour mémoire et pour votre commodité, je vais coller les parties principales de l'exemple du printemps:

@Projection(name = "inlineAddress", types = { Person.class }) 
interface InlineAddress {
  String getFirstName();
  String getLastName();
  Address getAddress(); 
}

voir à Projection javadoc que types signifie Le type auquel le type de projection est lié.
Le extrait pourrait être utilisé de cette façon:

@RepositoryRestResource(excerptProjection = InlineAddress.class)
interface PersonRepository extends CrudRepository<Person, Long> {}

afin d'obtenir ceci (en utilisant également MyRepositoryRestMvcConfiguration):

{
  "firstName" : "Frodo",
  "lastName" : "Baggins",
  "address" : { 
    "street": "Bag End",
    "state": "The Shire",
    "country": "Middle Earth"
  }
}

Pour vous, le sector est l'équivalent de address.

Notes finales

Lors du retour des tableaux, le _links le champ ne sera pas supprimé (c'est trop intrusif pour le faire); à la fin, vous aurez quelque chose comme ça:

{
    "_embedded" : {
        "persons" : [ {person1}, {person2}, ..., {personN} ]
    },
    "_links" : {
        e.g. first, next, last, self, profile
    },
    "page" : {
      "size" : 1,
      "totalElements" : 10,
      "totalPages" : 10,
      "number" : 0
    }
}

Comme vous pouvez le voir, même si nous aurions _links supprimé qui ne sera toujours pas suffisant; on voudrait probablement aussi _embedded remplacé par persons ce qui conduirait à un code moins facile à maintenir (trop de remplacements intrusifs de ressort). Mais si on le veut vraiment aussi, il devrait commencer à vérifier RepositoryRestMvcConfiguration et RepositoryEntityController.getCollectionResource.

Le printemps évolue donc je ressens le besoin de souligner que cela fonctionne avec au moins:

spring-data-rest-webmvc 3.1.3.RELEASE

ou, si vous préférez la version Spring Boot:

spring-boot-starter-parent 2.1.1.RELEASE
2
adrhc