web-dev-qa-db-ja.com

JSONでハイパーテキストアプリケーション言語(HAL)を無効にしますか?

バージョン2.0.2.RELEASEのJPAでSpring Data RESTを使用する。

JSONでハイパーテキストアプリケーション言語(HAL)を無効にするにはどうすればよいですか? http://stateless.co/hal_specification.html

すでに多くのことを試しましたが、役に立ちませんでした。たとえば、AcceptおよびContent-typeヘッダーを「application/hal + json」ではなく「application/json」に設定しましたが、ハイパーリンク付きのJSONコンテンツを受け取ります。

たとえば、次のようなものを取得したいです。

{
"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
     }
}

の代わりに:

{
"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"
     }
}
}

ご協力いただきありがとうございます。

37
jplandrain

(ハイパー)メディアタイプ

Spring Data REST=のデフォルト設定はデフォルトのハイパーメディア表現形式としてHALを使用するため、サーバーは指定されたAcceptヘッダーに対して以下を返します。

  • ヘッダーなし-> _application/hal+json_-> HAL
  • _application/hal+json_-> _application/hal+json_-> HAL
  • _application/json_-> _application/json_-> HAL(これはデフォルトの設定です)
  • _application/x-spring-data-verbose+json_-> _application/x-spring-data-verbose+json_-> Spring Data固有の形式(リンクコンテナにlinksを使用し、コレクションアイテムのラッパーとしてcontentを使用).

RepositoryRestConfiguration.setDefaultMediaType(…)を非HAL形式に設定すると、_application/hal+json_を明示的に要求しない限り、サーバーはSpring Data固有のJSON形式を返します。確かに、構成オプションはおそらく少し誤解を招く可能性があるので、これを改善するために DATAREST-294 を提出しました。この問題は、2.1 RC1(Dijkstra)2014で解決されました。

管理対象リソース間の関係を表現し、サーバーを検出できるようにするには、ハイパーメディア形式が効果的に必要であることに注意してください。そのため、完全に取り除くことはできません。これは主に、双方向の関係を持つエンティティを公開したり、巨大なオブジェクトグラフを作成したりすると、サーバーを簡単にクラッシュさせる可能性があるためです。

関連エンティティのインライン化

セクターをリンクせず、常にインラインにしたくない場合、1つのオプションは、最初にSectorRepositoryをRESTリソースとしてエクスポートされることから除外することです。これを実現するには、リポジトリインターフェイスに@RepositoryRestResource(exported = false)注釈を付けます。

下の例で投稿したとおりに表現を返すには、Spring Dataで導入された projections 機能をご覧くださいREST 2.1 M1。基本的にはオプションで作成できます。単純なインターフェースを介してデフォルトのリソースと異なる可能性のあるリソースのビュー。

基本的にインターフェイスを定義します:

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

  // list all other properties

  Sector getSector();
}
_

このインターフェイスをドメインクラスの(サブ)パッケージに入れるか、RepositoryRestConfiguration.projectionConfiguration()を介して手動で登録する場合、YourDomainClassを公開するリソースはリクエストパラメーターprojectionを受け入れるため、この例でfooを渡すと、インライン表現が希望どおりにレンダリングされます。

このコミット には一般的な機能に関する詳細があります。 このコミット にはプロジェクションの例が定義されています。

36
Oliver Drotbohm

だからあなたは2つのものが欲しい:

1)_linksフィールドを削除します
2)関連するsectorフィールドを含める

可能な解決策(私のために働く:D)

1)_linksを取り除く
このために、以下のクラスを作成します。

[... 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();
            }
        };
    }
}

そしてそれを使用します:

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

関連するエンティティ/エンティティincluded_linksを削除するためにこのクラスを必要としないことはかなり確信しています(99%、しかしテストされていません)次のポイント(2)が表示されています。

2)関連するsectorフィールドを含める
これには、 抜粋 (特にこのシナリオ用に作成)を使用できます。 Springの例は非常に雄弁であり、ここにコピーするのはばかげているので、それを指摘するだけにします。 https://docs.spring.io/spring-data/rest/docs/3.1.x/reference/ html /#projections-excerpts.excerpting-commonly-accessed-data
ただし、記録と利便性のために、春の例の主要部分を貼り付けます。

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

Projection javadoc を参照してください。typesは、投影タイプがバインドされているタイプを意味します。
excerptは次のように使用できます。

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

これを取得するには(MyRepositoryRestMvcConfigurationも使用する場合):

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

あなたにとってsectoraddressと同等です。

最終ノート

配列を返す場合、_linksフィールドは削除されません(邪魔になりすぎて実行できません)。最終的には次のようになります。

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

ご覧のとおり、_linksを削除しても十分ではありません。おそらく_embeddedpersonsで置き換えると、保守性の低いコードになります(あまりにも多くの春の邪魔なオーバーライド)。しかし、これらが本当に必要な場合は、RepositoryRestMvcConfigurationRepositoryEntityController.getCollectionResourceのチェックを開始する必要があります。

春は進化しているので、少なくともこれで機能することを指摘する必要があると感じています。

spring-data-rest-webmvc 3.1.3.RELEASE

または、スプリングブートバージョンを優先する場合:

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