web-dev-qa-db-ja.com

Spring REST、JSON「マネージ/バック参照 'defaultReference'を処理できません」415サポートされていないメディアタイプ

Spring Boot/Spring RestControllerバックエンドを使用して、AngularJSフロントエンドからPOST to http:// localhost:9095/translators をしようとしています。

私は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を投稿すると、error応答が返されます

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警告15152 --- [nio-9095-exec-1] .cjMappingJackson2HttpMessageConverter:タイプ[シンプルタイプ、クラスユーザー]の逆シリアル化の評価に失敗しました:Java.lang.IllegalArgumentException:できませんマネージ型/後方参照 'defaultReference'の処理:マネージ型(ユーザー)と互換性のない後方参照型(Java.util.List)

これが私のクラスUserとクラスTranslationです(簡潔にするために、getter、setter、コンストラクタなどは省略しています)。

@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を正しく設定するにはどうすればよいですか? doc。 を読みましたが、エラーメッセージに基づいてここで何が問題なのかを理解できません

15
senseiwu

JsonManagedReferenceとJsonBackReferenceを取り除き、JsonIdentityInfoで置き換えることで解決しました

6
senseiwu

@Sharppointがコメントで言ったように、私は@JsonManagedReferenceただし、保持@JsonBackReference

16

質問がある場合、別の方法としては、fasterxmlの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;
}

*コメントするのに十分な担当者がいませんでした。

10
Simon Lippens

次のような@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);
    }
4
sndyuk

これを解決するには、基本クラスのJsonManagedReferenceを削除します。 @JsonBackReferenceは、コントローラーからデータを取得/ポストしている間、無限に再帰を停止する作業を行います。

言語クラスには複数の@JsonBackReferenceが含まれていると想定しています。したがって、2つのクラスが含まれているユーザーデータを送信すると、Springはオブジェクトを逆シリアル化してそれに応じてマッピングできません。

これを解決するには、翻訳/言語クラスから@JsonBackReferenceの1つを削除し、@JsonIgnore/@JsonIdentityInfoに置き換えます。

このように、文字通り同じマッピングを行っていますが、代わりに、複数の@JsonBackReferenceを基本クラスに除外します。これにより、415 Unsupported media type exceptionのエラーとして明確に指摘されます。

0
sai kiran

同じバグがあり、すべてのアノテーション@JsonBackReferenceと@JsonManagedReferenceを削除することを解決した後、関係のあるすべてのクラスに@JsonIdentityInfoを配置しました Documentation を確認します

0
Lupita Llamas