दुर्भाग्यवश, 2.1.0.RELEASE तक सभी स्प्रिंग डेटा जेपीए/रेस्ट संस्करण बॉक्स से आपकी आवश्यकता को पूरा करने में सक्षम नहीं हैं। स्रोत को स्प्रिंग डेटा कॉमन्स/जेपीए के अंदर ही दफनाया गया है। स्प्रिंग डेटा जेपीए पहचानकर्ता के रूप में केवल Id
और EmbeddedId
का समर्थन करता है।
अंश JpaPersistentPropertyImpl
:
static {
// [...]
annotations = new HashSet<Class<? extends Annotation>>();
annotations.add(Id.class);
annotations.add(EmbeddedId.class);
ID_ANNOTATIONS = annotations;
}
स्प्रिंग डाटा कॉमन्स संयुक्त गुण की धारणा का समर्थन नहीं करता। यह एक दूसरे से स्वतंत्र रूप से कक्षा की हर संपत्ति का इलाज करता है।
बेशक, आप स्प्रिंग डेटा रेस्ट को हैक कर सकते हैं। लेकिन यह बोझिल है, समस्या को हल नहीं करता है और ढांचे की लचीलापन को कम करता है।
यहां हैक है। यह आपको एक समस्या दे सकता है कि आपकी समस्या से निपटने के लिए कैसे।
आपकी कॉन्फ़िगरेशन में repositoryExporterHandlerAdapter
ओवरराइड करें और CustomPersistentEntityResourceAssemblerArgumentResolver
लौटाएं। साथ ही, backendIdConverterRegistry
ओवरराइड और ज्ञात id converter
की सूची में CustomBackendIdConverter
जोड़ें:
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.rest.core.projection.ProxyProjectionFactory;
import org.springframework.data.rest.webmvc.RepositoryRestHandlerAdapter;
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
import org.springframework.data.rest.webmvc.spi.BackendIdConverter;
import org.springframework.data.rest.webmvc.support.HttpMethodHandlerMethodArgumentResolver;
import org.springframework.data.web.config.EnableSpringDataWebSupport;
import org.springframework.hateoas.ResourceProcessor;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.plugin.core.OrderAwarePluginRegistry;
import org.springframework.plugin.core.PluginRegistry;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@Configuration
@Import(RepositoryRestMvcConfiguration.class)
@EnableSpringDataWebSupport
public class RestConfig extends RepositoryRestMvcConfiguration {
@Autowired(required = false) List<ResourceProcessor<?>> resourceProcessors = Collections.emptyList();
@Autowired
ListableBeanFactory beanFactory;
@Override
@Bean
public PluginRegistry<BackendIdConverter, Class<?>> backendIdConverterRegistry() {
List<BackendIdConverter> converters = new ArrayList<BackendIdConverter>(3);
converters.add(new CustomBackendIdConverter());
converters.add(BackendIdConverter.DefaultIdConverter.INSTANCE);
return OrderAwarePluginRegistry.create(converters);
}
@Bean
public RequestMappingHandlerAdapter repositoryExporterHandlerAdapter() {
List<HttpMessageConverter<?>> messageConverters = defaultMessageConverters();
configureHttpMessageConverters(messageConverters);
RepositoryRestHandlerAdapter handlerAdapter = new RepositoryRestHandlerAdapter(defaultMethodArgumentResolvers(),
resourceProcessors);
handlerAdapter.setMessageConverters(messageConverters);
return handlerAdapter;
}
private List<HandlerMethodArgumentResolver> defaultMethodArgumentResolvers()
{
CustomPersistentEntityResourceAssemblerArgumentResolver peraResolver = new CustomPersistentEntityResourceAssemblerArgumentResolver(
repositories(), entityLinks(), config().projectionConfiguration(), new ProxyProjectionFactory(beanFactory));
return Arrays.asList(pageableResolver(), sortResolver(), serverHttpRequestMethodArgumentResolver(),
repoRequestArgumentResolver(), persistentEntityArgumentResolver(),
resourceMetadataHandlerMethodArgumentResolver(), HttpMethodHandlerMethodArgumentResolver.INSTANCE,
peraResolver, backendIdHandlerMethodArgumentResolver());
}
}
CustomBackendIdConverter
बनाएँ।यह वर्ग अपने कस्टम इकाई आईडी प्रतिपादन के लिए जिम्मेदार है:
import org.springframework.data.rest.webmvc.spi.BackendIdConverter;
import java.io.Serializable;
public class CustomBackendIdConverter implements BackendIdConverter {
@Override
public Serializable fromRequestId(String id, Class<?> entityType) {
return id;
}
@Override
public String toRequestId(Serializable id, Class<?> entityType) {
if(entityType.equals(Customer.class)) {
Customer c = (Customer) id;
return c.getId() + "_" +c.getStartVersion();
}
return id.toString();
}
@Override
public boolean supports(Class<?> delimiter) {
return true;
}
}
CustomPersistentEntityResourceAssemblerArgumentResolver
बारी में एक CustomPersistentEntityResourceAssembler
लौटना चाहिए:
import org.springframework.core.MethodParameter;
import org.springframework.data.repository.support.Repositories;
import org.springframework.data.rest.core.projection.ProjectionDefinitions;
import org.springframework.data.rest.core.projection.ProjectionFactory;
import org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler;
import org.springframework.data.rest.webmvc.config.PersistentEntityResourceAssemblerArgumentResolver;
import org.springframework.data.rest.webmvc.support.PersistentEntityProjector;
import org.springframework.hateoas.EntityLinks;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.ModelAndViewContainer;
public class CustomPersistentEntityResourceAssemblerArgumentResolver extends PersistentEntityResourceAssemblerArgumentResolver {
private final Repositories repositories;
private final EntityLinks entityLinks;
private final ProjectionDefinitions projectionDefinitions;
private final ProjectionFactory projectionFactory;
public CustomPersistentEntityResourceAssemblerArgumentResolver(Repositories repositories, EntityLinks entityLinks,
ProjectionDefinitions projectionDefinitions, ProjectionFactory projectionFactory) {
super(repositories, entityLinks,projectionDefinitions,projectionFactory);
this.repositories = repositories;
this.entityLinks = entityLinks;
this.projectionDefinitions = projectionDefinitions;
this.projectionFactory = projectionFactory;
}
public boolean supportsParameter(MethodParameter parameter) {
return PersistentEntityResourceAssembler.class.isAssignableFrom(parameter.getParameterType());
}
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
String projectionParameter = webRequest.getParameter(projectionDefinitions.getParameterName());
PersistentEntityProjector projector = new PersistentEntityProjector(projectionDefinitions, projectionFactory,
projectionParameter);
return new CustomPersistentEntityResourceAssembler(repositories, entityLinks, projector);
}
}
CustomPersistentEntityResourceAssembler
जरूरतों getSelfLinkFor
ओवरराइड करने के लिए। जैसा कि आप देख सकते हैं entity.getIdProperty()
या तो Customer
कक्षा की आईडी या स्टार्टवर्सन प्रॉपर्टी लौटाएं जो बदले में BeanWrapper
की सहायता से वास्तविक मूल्य को पुनर्प्राप्त करने के लिए उपयोग की जाती है। यहां हम instanceof
ऑपरेटर के उपयोग के साथ पूरे ढांचे को शॉर्ट सर्किट कर रहे हैं। इसलिए आगे की प्रक्रिया के लिए Customer
वर्ग को Serializable
लागू करना चाहिए।
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.model.BeanWrapper;
import org.springframework.data.repository.support.Repositories;
import org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler;
import org.springframework.data.rest.webmvc.support.Projector;
import org.springframework.hateoas.EntityLinks;
import org.springframework.hateoas.Link;
import org.springframework.util.Assert;
public class CustomPersistentEntityResourceAssembler extends PersistentEntityResourceAssembler {
private final Repositories repositories;
private final EntityLinks entityLinks;
public CustomPersistentEntityResourceAssembler(Repositories repositories, EntityLinks entityLinks, Projector projector) {
super(repositories, entityLinks, projector);
this.repositories = repositories;
this.entityLinks = entityLinks;
}
public Link getSelfLinkFor(Object instance) {
Assert.notNull(instance, "Domain object must not be null!");
Class<? extends Object> instanceType = instance.getClass();
PersistentEntity<?, ?> entity = repositories.getPersistentEntity(instanceType);
if (entity == null) {
throw new IllegalArgumentException(String.format("Cannot create self link for %s! No persistent entity found!",
instanceType));
}
Object id;
//this is a hack for demonstration purpose. don't do this at home!
if(instance instanceof Customer) {
id = instance;
} else {
BeanWrapper<Object> wrapper = BeanWrapper.create(instance, null);
id = wrapper.getProperty(entity.getIdProperty());
}
Link resourceLink = entityLinks.linkToSingleResource(entity.getType(), id);
return new Link(resourceLink.getHref(), Link.REL_SELF);
}
}
यही है! ,
{
"_embedded" : {
"customers" : [ {
"name" : "test",
"_links" : {
"self" : {
"href" : "http://localhost:8080/demo/customers/1_1"
}
}
} ]
}
}
IMHO अगर आप एक ग्रीन फील्ड परियोजना पर काम कर रहे हैं मैं पूरी तरह IdClass
खाई और तकनीकी सरल लांग वर्ग के आधार पर आईडी के साथ जाने के लिए सुझाव है: आप इस यूआरआई देखना चाहिए। इसका परीक्षण स्प्रिंग डेटा रेस्ट 2.1.0.RELEASE, स्प्रिंग डेटा जेपीए 1.6.0.RELEASE और स्प्रिंग फ्रेमवर्क 4.0.3.RELEASE के साथ किया गया था।
जाने का सबसे अच्छा तरीका कोई समस्या नहीं है। यह एक दिलचस्प समस्या है। आशा करता हूँ की ये काम करेगा। हो सकता है कि आपको अपनी आईडी को deserialize करने के लिए 'सेRequestId' को लागू करने की आवश्यकता हो। –
अच्छा जवाब! मैंने अभी भी कोशिश नहीं की है, लेकिन यह भंडार POST अनुरोध स्वीकार करेगा? मैं आरईएसटी एपीआई के माध्यम से डेटा कैसे डाल सकता हूं? –