স্প্রিং বুট @ রেসপনসবিডি সত্তা আইডিকে ক্রমিকায়িত করে না


97

একটি আশ্চর্যজনক সমস্যা আছে এবং এটি কীভাবে মোকাবেলা করতে হবে তা অনুমান করতে পারছি না। সহজ পোজো আছে:

@Entity
@Table(name = "persons")
public class Person {

    @Id
    @GeneratedValue
    private Long id;

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

    @Column(name = "middle_name")
    private String middleName;

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

    @Column(name = "comment")
    private String comment;

    @Column(name = "created")
    private Date created;

    @Column(name = "updated")
    private Date updated;

    @PrePersist
    protected void onCreate() {
        created = new Date();
    }

    @PreUpdate
    protected void onUpdate() {
        updated = new Date();
    }

    @Valid
    @OrderBy("id")
    @OneToMany(mappedBy = "person", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<PhoneNumber> phoneNumbers = new ArrayList<>();

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getMiddleName() {
        return middleName;
    }

    public void setMiddleName(String middleName) {
        this.middleName = middleName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    public Date getCreated() {
        return created;
    }

    public Date getUpdated() {
        return updated;
    }

    public List<PhoneNumber> getPhoneNumbers() {
        return phoneNumbers;
    }

    public void addPhoneNumber(PhoneNumber number) {
        number.setPerson(this);
        phoneNumbers.add(number);
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
    }
}

@Entity
@Table(name = "phone_numbers")
public class PhoneNumber {

    public PhoneNumber() {}

    public PhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    @Id
    @GeneratedValue
    private Long id;

    @Column(name = "phone_number")
    private String phoneNumber;

    @ManyToOne
    @JoinColumn(name = "person_id")
    private Person person;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
    }
}

এবং বিশ্রামের সমাপ্তি:

@ResponseBody
@RequestMapping(method = RequestMethod.GET)
public List<Person> listPersons() {
    return personService.findAll();
}

জসন প্রতিক্রিয়াতে আইডি ব্যতীত সমস্ত ক্ষেত্র রয়েছে যা ব্যক্তি সম্পাদনা / মুছতে আমার প্রথম প্রান্তে প্রয়োজন। আইডির পাশাপাশি সিরিয়াল করতে আমি কীভাবে বসন্ত বুট কনফিগার করতে পারি?

প্রতিক্রিয়া এখন দেখতে কেমন লাগে:

[{
  "firstName": "Just",
  "middleName": "Test",
  "lastName": "Name",
  "comment": "Just a comment",
  "created": 1405774380410,
  "updated": null,
  "phoneNumbers": [{
    "phoneNumber": "74575754757"
  }, {
    "phoneNumber": "575757547"
  }, {
    "phoneNumber": "57547547547"
  }]
}]

ইউপিডি দ্বি নির্দেশমূলক হাইবারনেট ম্যাপিং রয়েছে, সম্ভবত এটি কোনওভাবে ইস্যু সম্পর্কিত।


আপনি কি আমাদের বসন্ত সেটআপ সম্পর্কে আরও অন্তর্দৃষ্টি দিতে পারেন? আপনি কোন জসন মার্শালার ব্যবহার করেন? ডিফল্ট, জ্যাকসন, ...?
ওটা

আসলে বিশেষ কোনও সেটআপ নেই। স্প্রিং বুট চেষ্টা করে দেখতে চেয়েছিলেন :) পোম-তে স্প্রিং-বুট-স্টার্টার-ডেটা-বিশ্রাম যুক্ত হয়েছে এবং এটি সমস্তই @EableAutoConfigration ব্যবহার করে। কয়েকটি টিউটোরিয়াল পড়ুন এবং মনে হচ্ছে সকলকে বাক্সের বাইরে কাজ করতে হবে। এবং এটি, আইডি ক্ষেত্রটি বাদে। শেষ পয়েন্ট প্রতিক্রিয়া সহ আপডেট পোস্ট।
কনস্টান্টিন

4
স্প্রিং 4 এ আপনার @RestControllerনিয়ামক শ্রেণিতেও ব্যবহার করা উচিত এবং @ResponseBodyপদ্ধতিগুলি থেকে সরিয়ে নেওয়া উচিত। এছাড়াও আমি ডোমেন অবজেক্টের পরিবর্তে জেসন অনুরোধ / প্রতিক্রিয়াগুলি পরিচালনা করতে ডিটিও ক্লাস করার পরামর্শ দেব।
ভ্যালির

উত্তর:


141

আমার সম্প্রতি একই সমস্যা হয়েছিল এবং এটি কারণ এটি spring-boot-starter-data-restডিফল্টরূপে কীভাবে কাজ করে। আমার এসও প্রশ্নটি দেখুন -> স্প্রিং বুটে কোনও অ্যাপ্লিকেশন স্থানান্তরিত করার পরে স্প্রিং ডেটা রেস্ট ব্যবহার করার সময়, আমি পর্যবেক্ষণ করেছি যে @ আইডিসহ সত্তা বৈশিষ্ট্যগুলি আর জেএসএন-তে মার্শাল করা হবে না

এটি কীভাবে আচরণ করে তা কাস্টমাইজ করতে, আপনি RepositoryRestConfigurerAdapterনির্দিষ্ট শ্রেণীর জন্য আইডি প্রকাশ করতে প্রসারিত করতে পারেন ।

import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;

@Configuration
public class RepositoryConfig extends RepositoryRestConfigurerAdapter {
    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        config.exposeIdsFor(Person.class);
    }
}

4
এবং সত্তা শ্রেণিতে আইডিটির জন্য এখন গেটর এবং সেটার সমর্থন করতে ভুলবেন না! .. (আমি এটি ভুলে গিয়েছি এবং এর জন্য অনেক বেশি সময় সন্ধান করছিলাম)
ফিল

4
এটি coudnt RepositoryRestConfigurerAdapter মধ্যেorg.springframework.data.rest.webmvc.config
গোবিন্দ সিং

4
উৎপাদ: The type RepositoryRestConfigurerAdapter is deprecated। এছাড়াও কাজ করতে দেখা যায় না
গ্রীনএজজেড

4
প্রকৃতপক্ষে RepositoryRestConfigurerAdapterসর্বশেষ সংস্করণগুলিতে RepositoryRestConfigurerimplements RepositoryRestConfigurerextends RepositoryRestConfigurerAdapter
হ্রাস

49

যদি আপনাকে সমস্ত সত্তার জন্য শনাক্তকারীদের প্রকাশ করতে হয় :

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer;

import javax.persistence.EntityManager;
import javax.persistence.metamodel.Type;

@Configuration
public class RestConfiguration implements RepositoryRestConfigurer {

    @Autowired
    private EntityManager entityManager;

    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        config.exposeIdsFor(
                entityManager.getMetamodel().getEntities().stream()
                .map(Type::getJavaType)
                .toArray(Class[]::new));
    }
}

নোট করুন যে 2.1.0.RELEASEআপনার আগে স্প্রিং বুটের সংস্করণগুলিতে সরাসরি প্রয়োগের পরিবর্তে (এখন হ্রাস করা) প্রসারিত করতে হবে ।org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapterRepositoryRestConfigurer


যদি আপনি কেবল সুনির্দিষ্ট সুপার ক্লাস বা ইন্টারফেসকে প্রসারিত বা প্রয়োগ করে এমন সত্তার সনাক্তকারীদের প্রকাশ করতে চান :

    ...
    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        config.exposeIdsFor(
                entityManager.getMetamodel().getEntities().stream()
                .map(Type::getJavaType)
                .filter(Identifiable.class::isAssignableFrom)
                .toArray(Class[]::new));
    }

আপনি যদি সুনির্দিষ্ট টীকায়িত সংস্থার সনাক্তকারীদের প্রকাশ করতে চান :

    ...
    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        config.exposeIdsFor(
                entityManager.getMetamodel().getEntities().stream()
                .map(Type::getJavaType)
                .filter(c -> c.isAnnotationPresent(ExposeId.class))
                .toArray(Class[]::new));
    }

নমুনা টিকা:

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExposeId {}

যদি কোনও কোডের প্রথম ব্লক ব্যবহার করে তবে এটি কোন ডিরেক্টরি এবং ফাইলের মধ্যে যেতে পারে?
ডেভিড ক্রিডার

4
@ ডেভিডক্রিডার: কম্পোনেন্ট স্ক্যানের আওতাভুক্ত যে কোনও ডিরেক্টরিতে এটি নিজস্ব ফাইলে থাকা উচিত । আপনার মূল অ্যাপের নীচে যে কোনও উপ প্যাকেজ ( @SpringBootApplicationটিকা সহ) ভাল হতে হবে be
lcnicolau

Field entityManager in com.myapp.api.config.context.security.RepositoryRestConfig required a bean of type 'javax.persistence.EntityManager' that could not be found.
দিমিত্রি কোপ্রিভা

আমি যোগ করার চেষ্টা করেছেন @ConditionalOnBean(EntityManager.class)যে MyRepositoryRestConfigurerAdapter, কিন্তু পদ্ধতি বলা হয় না এবং আইডি এখনও উন্মুক্ত করা হয় না। আমি বসন্তের ডেটা মাইবাটিসের সাথে স্প্রিং ডেটা ব্যবহার করি: github.com/hatunet/spring-data-mybatis
Dimitri Kopriwa

@ দিমিত্রিকোপ্রিভা: EntityManagerএটি জেপিএর নির্দিষ্টকরণের অংশ এবং মাইবাটিস জেপিএ প্রয়োগ করে না ( মাইবাতিস কী জেপিএ অনুসরণ করে? ) একবার দেখুন? সুতরাং, আমি মনে করি গ্রহণযোগ্য উত্তরেরconfig.exposeIdsFor(...) মতো পদ্ধতিটি ব্যবহার করে আপনার সমস্ত সত্ত্বাকে এক করে কনফিগার করা উচিত ।
lcnicolau

24

@ এরিক-পেলাডান থেকে দেওয়া উত্তরটি বাক্সটির বাইরে চলে আসে নি, তবে এটি খুব কাছে ছিল, সম্ভবত এটি স্প্রিং বুটের আগের সংস্করণগুলির জন্য কাজ করেছিল। পরিবর্তে এখন এটি কনফিগার করা উচিত, আমি ভুল হলে আমাকে সংশোধন করুন:

import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;

@Configuration
public class RepositoryConfiguration extends RepositoryRestConfigurerAdapter {

    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        config.exposeIdsFor(User.class);
        config.exposeIdsFor(Comment.class);
    }
}

4
নিশ্চিত করা হয়েছে যে এই সমাধানটি স্প্রিং বুট v1.3.3 এর অধীনে ভাল কাজ করে RE
পলিয়াকফ 23

4

স্প্রিং বুট আপনি প্রসারিত করতে হবে SpringBootRepositoryRestMvcConfiguration
যদি আপনি ব্যবহার RepositoryRestMvcConfiguration application.properties মধ্যে কনফিগারেশন নির্ধারণ কাজ নাও করতে পারে

@Configuration
public class MyConfiguration extends SpringBootRepositoryRestMvcConfiguration  {

@Override
protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
    config.exposeIdsFor(Project.class);
}
}

তবে অস্থায়ী প্রয়োজনের জন্য আপনি সিরিয়ালাইজেশনে আইডি অন্তর্ভুক্ত করতে প্রক্ষেপণটি ব্যবহার করতে পারেন :

@Projection(name = "allparam", types = { Person.class })
public interface ProjectionPerson {
Integer getIdPerson();
String getFirstName();
String getLastName();

}


বসন্ত বুট 2 এ, এটি কাজ করে না। শ্রেণীর রেপোজিটরিআরস্টএমভিসি কনফিগারেশনের ওভাররাইডের জন্য কনফিগারেশনরেপোজিটরিআরস্টকনফাইগ্রেশন নেই।
পিচব্ল্যাক 408

4

ক্লাসটি RepositoryRestConfigurerAdapter৩.১.২০১ since সাল থেকে অবহেলা করা হয়েছে, RepositoryRestConfigurerসরাসরি প্রয়োগ করুন ।

@Configuration
public class RepositoryConfiguration implements RepositoryRestConfigurer  {
	@Override
	public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
		config.exposeIdsFor(YouClass.class);
		RepositoryRestConfigurer.super.configureRepositoryRestConfiguration(config);
	}
}

হরফ: https://docs.spring.io/spring-data/rest/docs/current-SNAPSHOT/api/org/springframework/data/rest/webmvc/config/RepositoryRestConfigurer.html


2

সহজ উপায়: আপনার ভেরিয়েবলটির নাম পরিবর্তন private Long id;করুনprivate Long Id;

আমার জন্য কাজ কর. আপনি এটি সম্পর্কে এখানে আরও পড়তে পারেন


13
ওহ, মানুষ ... এটি একটি কোড গন্ধ ... সত্যিই, এটি করবেন না
ইগোর ডোনিন

@ ইগরডোনিন বলেছেন যে জাভা সম্প্রদায়ের কাছে যারা ভেরিয়েবল / শ্রেণি / ফাংশন নামগুলি থেকে সর্বদা, সর্বত্র স্নিগ্ধ এবং শব্দার্থক শব্দগুলি পছন্দ করে loves
EralpB

2
@Component
public class EntityExposingIdConfiguration extends RepositoryRestConfigurerAdapter {

    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        try {
            Field exposeIdsFor = RepositoryRestConfiguration.class.getDeclaredField("exposeIdsFor");
            exposeIdsFor.setAccessible(true);
            ReflectionUtils.setField(exposeIdsFor, config, new ListAlwaysContains());
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

    class ListAlwaysContains extends ArrayList {

        @Override
        public boolean contains(Object o) {
            return true;
        }
    }
}

4
তাই আপনাকে স্বাগতম! যখন আপনার উত্তর কোড পোস্টিং যে, তা কিভাবে আপনার কোড ওপি এর সমস্যা :) solves ব্যাখ্যা করতে সহায়ক
জোএল

1

এইচএম, ঠিক আছে বলে মনে হচ্ছে সমাধান খুঁজে পেয়েছি। পোম ফাইল থেকে স্প্রিং-বুট-স্টার্টার-ডেটা-বিশ্রাম অপসারণ করা এবং ফোন নম্বরগুলিতে @ জেসন ম্যানেজড রেফারেন্স যুক্ত করা এবং ব্যক্তির কাছে @ জসনব্যাক রেফারেন্স পছন্দসই আউটপুট দেয়। প্রতিক্রিয়া হিসাবে জসন আর ভাল ছাপা হয় না তবে এখন এটি আইডি আছে। জানেন না যে ম্যাজিক স্প্রিং বুট এই নির্ভরতার সাথে হুডের অধীনে কী সম্পাদন করে তবে আমি এটি পছন্দ করি না :)


এটি আপনার স্প্রিং ডেটা সংগ্রহস্থলগুলিকে REST এন্ডপয়েন্টস হিসাবে প্রকাশ করার জন্য। আপনি যদি এই বৈশিষ্ট্যটি না চান তবে আপনি এটিটি ছেড়ে দিতে পারেন। আইডি জিনিসটি হল জ্যাকসনের সাথে করা Moduleযা আমি বিশ্বাস করি এসডিআর দ্বারা নিবন্ধিত।
ডেভ সায়ার

4
RESTful API এর সার্গেট কী আইডি প্রকাশ করা উচিত নয় কারণ এগুলি বাহ্যিক সিস্টেমে কিছুই বোঝায় না। RESTful আর্কিটেকচারে আইডি হ'ল সেই সংস্থানটির ক্যানোনিকাল URL।
ক্রিস ডেমর

4
আমি এটি আগেও পড়েছি, তবে সত্যই আমি বুঝতে পারি না আমি কীভাবে আইড ছাড়া সামনের ও শেষ প্রান্তটি সংযুক্ত করতে পারি। মুছতে / আপডেট অপারেশনের জন্য আমাকে orm এ আইডি দিতে হবে। হতে পারে আপনার কিছু লিঙ্ক রয়েছে, কীভাবে এটি সত্যিকারের উপায়ে করা যেতে পারে :)
কনস্ট্যান্টিন

0

আইডিতে কেবল @JsonProperty টীকা যুক্ত করুন এবং এটি কাজ করে।

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@JsonProperty
private long id;
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.