source

Spring REST, JSON "관리/백 참조 'defaultReference'를 처리할 수 없음" 415 지원되지 않는 미디어 유형

lovecheck 2023. 7. 1. 08:59
반응형

Spring REST, JSON "관리/백 참조 'defaultReference'를 처리할 수 없음" 415 지원되지 않는 미디어 유형

Angular에서 http://localhost:9095/translators에 게시하려고 합니다.스프링 부트/스프링 레스트 컨트롤러 백엔드를 사용하는 JS 프론트 엔드.

저는 GET를 할 수 있으며 다음과 같은 반응을 보입니다.

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

아래 json을 게시하면 오류 응답이 표시됩니다.

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

컨트롤러에 올바른 미디어 유형 주석이 있는지 확인했습니다.

@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.매핑 잭슨2HttpMessageConverter : [단순 유형, 클래스 사용자]: java.lang 유형에 대한 역직렬화를 평가하지 못했습니다.잘못된 인수예외:관리/백 참조 'defaultReference': 백 참조 유형(java.util)을 처리할 수 없습니다.목록) 관리되는 유형(사용자)과 호환되지 않습니다.

여기 제 클래스 사용자 및 클래스 번역이 있습니다(간단하게 설명하기 위해 getter, settter, constructor 등 생략).

@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를 올바르게 설정하려면 어떻게 해야 합니까?는 문서를 읽었습니다. 그리고 나는 오류 메시지를 바탕으로 여기서 무엇이 잘못되었는지 알 수 없습니다.

@Sharpoint가 댓글로 말했듯이, 저는 지뢰를 제거함으로써 해결했습니다.@JsonManagedReference하지만 계속@JsonBackReference.

질문하는 사람들을 위해, 다른 접근법은 fasterxml의 JsonIdentity를 사용하는 것입니다.다음을 사용하여 강의에 주석을 달 수 있습니다.

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;
}

*담당자가 부족하여 의견을 제시할 수 없습니다.

JsonManagedReference와 JsonBackReference를 제거하고 JsonIdentity로 교체하여 해결했습니다.정보

필요합니다@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);
    }

제거하면 이 문제를 해결할 수 있습니다.JsonManagedReference베이스 클래스에서 @JsonBackReference컨트롤러에서 데이터를 가져오거나 가져오는 동안 재귀를 무한정 중지하는 작업을 수행합니다.

에 여러 개의 Language가 합니다.@JsonBackReference그래서 두 개의 클래스가 포함된 사용자 데이터를 보낼 때 스프링은 객체를 역직렬화하고 그에 따라 매핑할 수 없습니다.

이 문제는 다음 중 하나를 제거하는 것만으로 해결할 수 있습니다.@JsonBackReference번역/언어 클래스에서 다음으로 대체합니다.@JsonIgnore/@JsonIdentityInfo.

이렇게 하면 문자 그대로 동일한 매핑을 수행하지만 대신 다중 매핑을 제외합니다.@JsonBackReference결과적으로 발생하는 오류로 명확하게 지적된 기본 클래스에415 Unsupported media type exception.

동일한 버그가 발생하여 모든 주석 @JsonBackReference 및 @JsonManagedReference를 제거하기로 결정한 다음 @JsonIdentity를 추가했습니다.관계가 있는 모든 클래스의 정보 설명서 확인

이 문제를 해결하는 또 다른 좋은 방법은@JsonView이 방법은 컨트롤러에 뷰 이름을 붙인 다음 해당 뷰에 표시할 속성에 레이블을 지정하는 것입니다.특히 호출 보기에 역참조 속성을 표시하지 않습니다.아래의 매우 단순화된 예는 다음과 같습니다.

당신이 이렇게 1대1 관계를 가졌다고 상상해보세요.이렇게 하면 순환 참조가 생성됩니다.

@Entity
public class Student {

  String name;
  Tutor tutor;

}

@Entity
public class Tutor {
  String name;
  Student student;

}

이제 거의 동일한 방법으로 사용자에 대한 보기를 만들 수 있습니다.@JsonIgnore그리고.@JsonProperty.

1단계. 컨트롤러에 태그를 지정하는 데 사용할 수 있는 임의의 빈 인터페이스를 만듭니다.

public class LearningController {

  @GetRequest("/tutors")
  @JsonView(TutorView.class) // create an empty interface with a useful name
  public Set<Tutor> tutors() {
    return tutorRepository.findAll()
  }

  @GetRequest("/students")
  @JsonView(StudentView.class) // create an empty interface with a useful name
  public Set<Student> students() {
    return studentRepository.findAll()
  }
}

2단계. (관련/참조된 클래스의) 뷰에 노출할 속성에 레이블을 지정합니다.@JsonView주석

@Entity
public class Student {

  @JsonView({StudentView.class, TutorView.class})
  String name;

  @JsonView({StudentView.class}) // Not visible to @TutorView (no backreference)
  Tutor tutor;

}

@Entity
public class Tutor {
  @JsonView({StudentView.class, TutorView.class})
  String name;
  @JsonView(TutorView.class) // Not visible to @StudentView (no backreference)
  Student student;
}

@JsonIgnore를 추가하여 유사한 사례를 해결했습니다.

언급URL : https://stackoverflow.com/questions/28179369/spring-rest-json-can-not-handle-managed-back-reference-defaultreference-415

반응형