Spring REST, JSON "Невозможно обработать управляемую/обратную ссылку" defaultReference "" 415 Неподдерживаемый тип носителя

Я пытаюсь выполнить POST для http://localhost:9095/translators внешнего интерфейса AngularJS с помощью внутреннего загрузчика Spring/Spring RestController.

Я могу сделать GET, и ответ будет следующим:

[{"userId":1,"firstName":"John","lastName":"Doe","emailId":"[email protected]","languages":[{"languageId":1,"languageCode":"gb","source":true}],"translations":[{"translationId":3,"sourceId":1,"sourceText":"Hello","targetId":null,"targetText":null,"translationStatus":"DUE"}],"userType":"TRANSLATOR"}

Когда я публикую нижеприведенный json, я получаю ответ об ошибке response

Данные POST:

{
                    firstName: "zen",
                    lastName: "cv",
                    emailId: "email",
                    userType: "TRANSLATOR",
                    languages : [{languageId:1,languageCode:"gb",source:true}]
}

Ошибка:

{
timestamp: 1422389312497
status: 415
error: "Unsupported Media Type"
exception: "org.springframework.web.HttpMediaTypeNotSupportedException"
message: "Content type 'application/json' not supported"
path: "/translators"
}

Я убедился, что у моего контроллера правильная аннотация Mediatype.

@RestController
@RequestMapping("/translators")
public class TranslatorController {
    @Autowired
    private UserRepository repository;

    @RequestMapping(method = RequestMethod.GET)
    public List findUsers() {
        return repository.findAll();
    }

    @RequestMapping(value = "/{userId}", method = RequestMethod.GET)
    public User findUser(@PathVariable Long userId) {
        return repository.findOne(userId);
    }

    @RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public User addTranslator(@RequestBody User user) {
        //translation.setTranslationId(null);
        return repository.saveAndFlush(user);
    }

    @RequestMapping(value = "/{translatorId}", method = RequestMethod.PUT)
    public User updateTranslation(@RequestBody User updatedUser, @PathVariable Long userId) {
        //updatedTranslation.setTranslationId(translationId);
        return repository.saveAndFlush(updatedUser);
    }

    @RequestMapping(value = "/{translatorId}", method = RequestMethod.DELETE)
    public void deleteTranslation(@PathVariable Long translationId) {
        repository.delete(translationId);
    }
}

После некоторых исследований, а также, увидев вывод журнала, я понимаю, что это вводящее в заблуждение сообщение об ошибке, и проблема фактически возникает при сериализации/десериализации Json

В лог файле я нахожу

2015-01-27 21: 08: 32.488 WARN 15152 --- [nio-9095-exec-1].c.j.MappingJackson2HttpMessageConverter: Не удалось оценить десериализация для типа [простой тип, класс User]: java.lang.IllegalArgumentException: не может обработать управляемый/назад ссылка 'defaultReference': тип обратной ссылки (java.util.List) нет совместим с управляемым типом (пользователь)

Вот мой класс User и класс Translation (геттер, сеттер, конструктор и т.д. Для краткости опущены)

@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    @Column(name = "user_id")
    private long userId;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "email_id")
    private String emailId;

    @ManyToMany
    @JoinTable(name = "languages_users", joinColumns = { @JoinColumn(name = "user_id")},
            inverseJoinColumns = {@JoinColumn(name = "lang_id")})
    @JsonManagedReference
    private List<Language> languages = new ArrayList<Language>();

    @OneToMany(mappedBy = "translator", fetch = FetchType.EAGER)
    @JsonManagedReference
    private List<Translation> translations;

    @Enumerated(EnumType.STRING)
    private UserType userType;
}

@Entity
@Table(name = "translations")
public class Translation {

    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    @Column(name = "translation_id")
    private Long translationId;

    @Column(name = "source_lang_id")
    private Long sourceId;

    @Column(name = "source_text")
    private String sourceText;

    @Column(name = "target_lang_id")
    private Long targetId;

    @Column(name = "target_text")
    private String targetText;

    @Enumerated(EnumType.STRING)
    @Column(name = "status")
    private TranslationStatus translationStatus;

    @ManyToOne
    @JoinColumn(name = "translator_id")
    @JsonBackReference
    private User translator;
}

У меня такой вопрос: как правильно установить JsonManagedReference и JsonBackReference для указанных выше объектов? Я прочитал документ. и не могу понять, что здесь не так, основываясь на сообщении об ошибке.

Ответ 1

Я решил его решить, избавившись от JsonManagedReference и JsonBackReference и заменив его на JsonIdentityInfo

Ответ 2

Как пояснил @Sharppoint в комментариях, я решил шахту, удалив @JsonManagedReference НО продолжаю @JsonBackReference.

Ответ 3

Для тех, альтернативным подходом было бы использовать quickxml JsonIdentityInfo и аннотировать ваш класс:

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
public class Account implements java.io.Serializable {
....
private Long id;
}

* Не хватало комментариев для комментариев.

Ответ 4

Вам нужна аннотация @ResponseBody, как показано ниже:

@RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody public User addTranslator(@RequestBody User user) {
        //translation.setTranslationId(null);
        return repository.saveAndFlush(user);
    }

Ответ 5

У меня была такая же ошибка, и я решил удалить все мои аннотации @JsonBackReference и @JsonManagedReference, а затем поместил @JsonIdentityInfo во все мои классы с отношениями Проверьте Документация

Ответ 6

Можно решить эту проблему, удалив JsonManagedReference из базового класса. @JsonBackReference выполняет работу по прекращению бесконечного повторения при получении/публикации данных с контроллера.

Я предполагаю, что в вашем классе Language несколько @JsonBackReference. Поэтому, когда вы отправляете пользовательские данные с двумя включенными в него классами, пружина не может десериализовать объект и отобразить его соответствующим образом.

Вы можете решить эту проблему, просто удалив один из @JsonBackReference из классов перевода/языка и заменив его на @JsonIgnore/@JsonIdentityInfo.

Таким образом, вы в буквальном смысле делаете то же самое отображение, но вместо этого вы исключаете множественный @JsonBackReference для базового класса, что явно указывается как ошибка, приводящая к 415 Unsupported media type exception.