jackson हाइबरनेट वैलीडेट और जैक्सन: @ जेसनप्रॉपर्टी वैल्यू का उपयोग करके प्रतिबंध उल्लंघन संसाधनपथ?




bean-validation hibernate-validator (2)

नहीं, यह संभव नहीं है हाइबरनेट वैल्यूएटर 5 (बीन वैलिडेशन 1.1) में ParameterNameProvider नामप्रदाता की धारणा है जो मामले में रिपोर्ट करने के लिए नाम लौटाते हैं क्योंकि पैरामीटर की बाधाओं का उल्लंघन होता है लेकिन संपत्ति बाधाओं के लिए तुलनीय नहीं है।

कहते हैं कि मेरे पास एक सरल पीओजो है जैसा नीचे जैक्सन 2.1 और सीतनिद्रा में होना मान्यकरण 4.3.1 एनोटेशन के साथ एनोटेट किया गया है:

final public class Person {
  @JsonProperty("nm")
  @NotNull
  final public String name;

  public Person(String name) {
      this.name = name;
  }
}

और मैं एक वेब सेवा जैसे JSON भेजता हूं:

{"name": null}

हाइबरनेट जब यह रिपोर्ट करता है कि संयम उल्लंघन ने वर्ग सदस्य पहचानकर्ता "नाम" का उपयोग करते हुए JsonProperty एनोटेशन मान का उपयोग किया है। क्या किसी को पता है कि क्या हाइबरनेट वैल्यूएटर क्लास के एनोटेशन को देखने के लिए संभव है और इसके बजाय उस मान का उपयोग करें?


दुर्भाग्य से ऐसा करने का कोई आसान तरीका नहीं है लेकिन यहां कुछ अंतर्दृष्टि हैं जो आपकी सहायता कर सकते हैं:

बाधा का उल्लंघन पार्सिंग

प्रतिबंध उल्लंघन से ConstraintViolationException , आप एक प्रतिबंध का उल्लंघन प्राप्त कर सकते हैं, जो बाधा उल्लंघन के संदर्भ को उजागर करता है:

  • ConstraintViolation#getLeafBean() : यदि यह एक बीन बाधा है, तो यह विधि बीन उदाहरण देता है जिसमें बाधा को लागू किया जाता है।
  • ConstraintViolation#getPropertyPath() : अमान्य संपत्ति के पथ को लौटाता है

संपत्ति पथ से, आप पत्ती नोड प्राप्त कर सकते हैं:

Path propertyPath = constraintViolation.getPropertyPath();
Optional<Path.Node> leafNodeOptional = 
        StreamSupport.stream(propertyPath.spliterator(), false).reduce((a, b) -> b);

फिर जांच लें कि नोड का प्रकार PROPERTY और उसका नाम प्राप्त करें:

String nodeName = null;

if (leafNodeOptional.isPresent()) {
    Path.Node leafNode = leafNodeOptional.get();
    if (ElementKind.PROPERTY == leafNode.getKind()) {
        nodeName = leafNode.getName();
    }
}

जैक्सन के साथ एक क्लास का परिचय

पत्ता बीन वर्ग से उपलब्ध JSON प्रॉपर्टी प्राप्त करने के लिए, आप जैक्सन के साथ इसे आत्मनिर्भर कर सकते हैं (इस उत्तर को और अधिक जानकारी के लिए यह उत्तर देखें):

Class<?> beanClass = constraintViolation.getLeafBean().getClass();
JavaType javaType = mapper.getTypeFactory().constructType(beanClass);

BeanDescription introspection = mapper.getSerializationConfig().introspect(javaType);
List<BeanPropertyDefinition> properties = introspection.findProperties();

फिर BeanPropertyDefinition से Field नाम के साथ पत्ती नोड नाम की तुलना करके गुणों को फ़िल्टर करें:

Optional<String> jsonProperty = properties.stream()
        .filter(property -> nodeName.equals(property.getField().getName()))
        .map(BeanPropertyDefinition::getName)
        .findFirst();

जेएक्स-आरएस का उपयोग करना?

JAX-RS के साथ (यदि आप इसे उपयोग कर रहे हैं), तो आप ConstraintViolationException को नियंत्रित करने के लिए एक ExceptionMapper को परिभाषित कर सकते हैं:

@Provider
public class ConstraintViolationExceptionMapper 
                 implements ExceptionMapper<ConstraintViolationException> {

    @Override
    public Response toResponse(ConstraintViolationException exception) {
        ...
    }
}

अपने ExceptionMapper में ContextResolver<T> उपयोग करने के लिए, आप इसके लिए एक ContextResolver<T> प्रदान कर सकते हैं:

@Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {

    private final ObjectMapper mapper;

    public ObjectMapperContextResolver() {
        mapper = createObjectMapper();
    }

    @Override
    public ObjectMapper getContext(Class<?> type) {
        return mapper;
    }

    private ObjectMapper createObjectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        return mapper;
    }
}

अपने ExceptionMapper में Providers इंटरफ़ेस को इंजेक्ट करें:

@Context
private Providers providers;

अपने ContextResolver<T> और फिर ContextResolver<T> उदाहरण प्राप्त करें:

ContextResolver<ObjectMapper> resolver = 
        providers.getContextResolver(ObjectMapper.class, MediaType.WILDCARD_TYPE);
ObjectMapper mapper = resolver.getContext(ObjectMapper.class);

यदि आप @XxxParam नाम प्राप्त करने में रुचि रखते हैं, तो इस उत्तर का संदर्भ लें।