Неожиданно возвращен json, ссылки написаны как _links и имеют другую структуру, в Spring ненавидят

Как следует из названия, у меня есть ресурсный объект Product, расширяющий ResourceSupport. Однако ответы, которые я получаю, имеют свойство «_links» вместо «links» и имеют другую структуру.

{
  "productId" : 1,
  "name" : "2",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/products/1"
    }
  }
}

На основании справочника HATEOAS ожидается следующее:

{
  "productId" : 1,
  "name" : "2",
  "links" : [
    {
      "rel" : "self"
      "href" : "http://localhost:8080/products/1"
    }
  ]
}

Это было задумано? Есть ли способ изменить его или хотя бы «ссылку», если не структуру?

Я добавил selfLink через следующий фрагмент:

product.add(linkTo(ProductController.class).slash(product.getProductId()).withSelfRel());

Я использую весеннюю загрузку со следующим файлом сборки:

dependencies {
    compile ("org.springframework.boot:spring-boot-starter-data-rest") {
        exclude module: "spring-boot-starter-tomcat"
    }

    compile "org.springframework.boot:spring-boot-starter-data-jpa"
    compile "org.springframework.boot:spring-boot-starter-jetty"
    compile "org.springframework.boot:spring-boot-starter-actuator"

    runtime "org.hsqldb:hsqldb:2.3.2"

    testCompile "junit:junit"
}

person Chad    schedule 21.08.2014    source источник
comment
Я вижу по крайней мере одно место на этой странице, где есть ссылка на часть _links, в CurieProvider API. Вы уверены, что всегда должны получать ссылки именно так, как вы думаете?   -  person Dave Newton    schedule 21.08.2014
comment
@Chad, вы указываете HAL с помощью чего-то вроде @EnableHypermediaSupport(type = HypermediaType.HAL)? Формат HAL json использует _links, но Spring по умолчанию — это просто ссылки.   -  person gyoder    schedule 21.08.2014
comment
Я вообще ничего не уточнял.   -  person Chad    schedule 22.08.2014
comment
Некоторое поведение недавно изменилось, так как в Spring Boot 1.2.8 и Spring HATEOAS 0.16.0 моя конфигурация дает мне _links, но если я обновляюсь до Spring Boot 1.3.1, я начинаю получать ссылки.   -  person Nick Spacek    schedule 13.01.2016
comment
Я использую Spring boot 1.5.4 и начинаю получать _Link. Проблема в том, что клиент Джерси не распознает структуру. Вы могли бы решить проблему?   -  person J. Abel    schedule 19.06.2018


Ответы (6)


Spring Boot сейчас (версия = 1.3.3.RELEASE) имеет свойство, которое управляет выходным форматом JSON файла PagedResources.

Просто добавьте следующую конфигурацию в ваш файл application.yml:

spring.hateoas.use-hal-as-default-json-media-type: false

если вам нужно, чтобы вывод был похож (на основе вопроса):

{
  "productId" : 1,
  "name" : "2",
  "links" : [
    {
      "rel" : "self"
      "href" : "http://localhost:8080/products/1"
    }
  ]
}

Отредактировано:

Кстати, вам нужна только аннотация @EnableSpringDataWebSupport таким образом.

person TonyLxc    schedule 15.06.2016

Другой вариант — отключить всю функцию автоматической настройки гипермедиа (как это делается в одном из примеров spring-boot + REST здесь):

@EnableAutoConfiguration(exclude = HypermediaAutoConfiguration.class)

Насколько я знаю, HypermediaAutoConfiguration на самом деле мало что делает, кроме настройки HAL, поэтому его вполне можно отключить.

person Priidu Neemre    schedule 14.08.2016
comment
отключение не меняет формат ссылок в файле json. - person brownfox; 30.06.2017
comment
@Phaneendra: ну, у меня это сработало на 100%. Но я предполагаю, что прошло время, поэтому я не уверен, что это решение актуально для более новых версий spring-boot. - person Priidu Neemre; 30.06.2017
comment
хм.. возможно.! Сейчас мне не разрешено менять голос.. упс! - person brownfox; 01.07.2017

Если у вас есть доступный HAL, он будет выбран для вас при весенней загрузке (и «_links» — это то, что вы получаете с HAL). Вы должны иметь возможность @EnableHypermediaSupport вручную переопределить значения по умолчанию.

person Dave Syer    schedule 21.08.2014
comment
Я проверил сегодня, и кажется, что @EnableHypermediaSupport требует тип HypermediaType. Но доступен только HAL - person Chad; 22.08.2014
comment
Я предполагаю, что по умолчанию не классифицируется как гипермедиа. Что произойдет, если вы @EnableHypermediaSupport не укажете тип? - person Dave Syer; 22.08.2014
comment
HAL, по-видимому, является типом гипермедиа по умолчанию. - person Chad; 23.08.2014
comment
Полагаю, тогда вам нужно не включать поддержку гипермедиа? - person Dave Syer; 23.08.2014

Я заметил, что проблема возникает, по крайней мере, когда вы пытаетесь вернуть объект, расширяющий ResourseSupport, и объект, содержащий объект, расширяющий ResourseSupport. Вы можете вернуть даже Список или Массив объектов, расширяющих ResourseSupport, и иметь тот же эффект. См. пример:

@RequestMapping(method = GET, value = "/read")
public NfcCommand statusPayOrder() {
    return generateNfcCommand();
}

есть ответ:

{
    "field": "123",
    "_links": {
        "self": {
            "href": "http://bla_bla_bla_url"
        }
    }
}

При попытке обернуть как список:

@RequestMapping(method = GET, value = "/read")
public List<NfcCommand> statusPayOrder() {
    return Arrays.asList(generateNfcCommand());
}

получающий:

[
    {
        "field": 123
        "links": [
            {
                "rel": "self",
                "href": "http://bla_bla_bla_url"
            }
        ]
    }
]

Менять структуру ответа — не самое правильное решение, но мы можем попробовать дальше мыслить в этом ключе.

person user2602807    schedule 29.09.2017
comment
Мне понадобился целый день, чтобы это выяснить. --- Спасибо за публикацию этого обновления! :) - person Peter; 28.03.2018

У меня недавно была противоположная проблема, я ожидал форму HAL (т.е. _links), но всегда получал links, хотя и использовал @EnableAutoConfiguration.

Решение моей проблемы может помочь и здесь. Из-за копирования и вставки из примера, который я нашел, у меня было два медиатипа в аннотации @RequestMapping моего RestController.

@RequestMapping(path="/example", produces = {MediaType.APPLICATION_JSON_VALUE, "application/hal+json"})

С @EnableAutoConfiguration Spring HATEOAS регистрирует ObjectMapper только для application/hal+json, а в моем приложении был еще один, ответственный за MediaType.APPLICATION_JSON_VALUE, который выиграл выбор и отрендерил стандартный JSON.

Поэтому мое решение установить только produces="application/hal+json", чтобы был выбран сопоставитель объектов Spring HATEOAS. В вашем случае вы должны попытаться сохранить MediaType.APPLICATION_JSON_VALUE

person rainer198    schedule 13.07.2018

Я уверен, что вы используете данные Spring с аннотацией @RepositoryRestResource

@RepositoryRestResource    
public interface XX extends CrudRepository<AA, String>

Если вы хотите удалить поведение HAL по умолчанию, вы можете добавить следующий параметр аннотации

@RepositoryRestResource(exported = false)
public interface XX extends CrudRepository<AA, String>

Приведенная выше конфигурация Spring Data REST предоставляет только конечные точки отдыха для ресурсов в родительском проекте, без необходимости явно аннотировать каждый репозиторий в проекте зависимостей.

Согласно документу

Скрытие определенных репозиториев, методов запроса или полей Возможно, вы вообще не хотите, чтобы определенный репозиторий, метод запроса в репозитории или поле вашей сущности экспортировались. Примеры включают скрытие таких полей, как пароль, в объекте пользователя или аналогичных конфиденциальных данных. Чтобы указать экспортеру не экспортировать эти элементы, аннотируйте их с помощью @RestResource и установите exported = false.

Например, чтобы пропустить экспорт репозитория:

@RepositoryRestResource(exported = false)
interface PersonRepository extends CrudRepository<Person, Long> {}
person vaquar khan    schedule 13.07.2017
comment
У меня та же проблема, и я не использую @RepositoryRestResource. - person user2602807; 29.09.2017