Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@
public class BeanDeserializerModifierWithValidation extends ValueDeserializerModifier {

private final Validator validator;
private final StrictnessMode strictnessMode;

@Override
public ValueDeserializer<?> modifyDeserializer(DeserializationConfig config,
Supplier beanDescRef,
ValueDeserializer<?> deserializer) {
if (deserializer instanceof BeanDeserializerBase) {
return new BeanDeserializerWithValidation(deserializer, validator);
return new BeanDeserializerWithValidation(deserializer, validator, strictnessMode);
}

return deserializer;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package de.rwth.idsg.ocpp.jaxb.validation;

import lombok.extern.slf4j.Slf4j;
import tools.jackson.core.JacksonException;
import tools.jackson.core.JsonParser;
import tools.jackson.databind.DeserializationContext;
Expand All @@ -13,18 +14,22 @@
/**
* https://www.baeldung.com/java-object-validation-deserialization
*/
@Slf4j
public class BeanDeserializerWithValidation extends DelegatingDeserializer {

private final Validator validator;
private final StrictnessMode strictnessMode;

protected BeanDeserializerWithValidation(ValueDeserializer<?> delegate, Validator validator) {
protected BeanDeserializerWithValidation(ValueDeserializer<?> delegate, Validator validator,
StrictnessMode strictnessMode) {
super(delegate);
this.validator = validator;
this.strictnessMode = strictnessMode;
}

@Override
protected ValueDeserializer<?> newDelegatingInstance(ValueDeserializer<?> newDelegate) {
return new BeanDeserializerWithValidation(newDelegate, validator);
return new BeanDeserializerWithValidation(newDelegate, validator, strictnessMode);
}

@Override
Expand All @@ -50,8 +55,14 @@ public Object deserializeWithType(JsonParser p, DeserializationContext ctxt, Typ

private <T> void validate(T object) {
var violations = validator.validate(object);
if (!violations.isEmpty()) {
throw new ConstraintViolationException(violations);
if (violations.isEmpty()) {
return;
}

var exception = new ConstraintViolationException(violations);
switch (strictnessMode) {
case LogWarning -> log.warn("There are constraint violations", exception);
case ThrowError -> throw exception;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@
public class BeanSerializerModifierWithValidation extends ValueSerializerModifier {

private final Validator validator;
private final StrictnessMode strictnessMode;

@Override
public ValueSerializer<?> modifySerializer(SerializationConfig config,
BeanDescription.Supplier beanDesc,
ValueSerializer<?> serializer) {
if (serializer instanceof BeanSerializerBase) {
return new BeanSerializerWithValidation((BeanSerializerBase) serializer, validator);
return new BeanSerializerWithValidation((BeanSerializerBase) serializer, validator, strictnessMode);
Comment on lines +16 to +23

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Breaking ctor signatures 🐞 Bug ⛯ Reliability

Public validation modifier classes now require a StrictnessMode parameter, which is a source/binary
incompatible change for any consumers constructing them directly. This can break downstream builds
without a clear migration path.
Agent Prompt
### Issue description
Public classes `BeanSerializerModifierWithValidation` / `BeanDeserializerModifierWithValidation` (and related wrappers) changed constructor signatures due to adding `strictnessMode` as a new final field under Lombok `@RequiredArgsConstructor`. This is a breaking change for downstream consumers who instantiate these classes directly.

### Issue Context
The library already provides `BeanValidationModule` factories for typical use, so you can either (a) keep public constructors stable via overloads/defaults, or (b) reduce surface area by making internal classes non-public and exposing stable factory APIs.

### Fix Focus Areas
- ocpp-jaxb/src/main/java/de/rwth/idsg/ocpp/jaxb/validation/BeanSerializerModifierWithValidation.java[12-27]
- ocpp-jaxb/src/main/java/de/rwth/idsg/ocpp/jaxb/validation/BeanDeserializerModifierWithValidation.java[15-30]
- ocpp-jaxb/src/main/java/de/rwth/idsg/ocpp/jaxb/validation/BeanSerializerWithValidation.java[14-39]
- ocpp-jaxb/src/main/java/de/rwth/idsg/ocpp/jaxb/validation/BeanDeserializerWithValidation.java[17-67]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

}

return serializer;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package de.rwth.idsg.ocpp.jaxb.validation;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import tools.jackson.core.JacksonException;
import tools.jackson.core.JsonGenerator;
import tools.jackson.databind.SerializationContext;
Expand All @@ -10,20 +11,31 @@
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Validator;

@Slf4j
@RequiredArgsConstructor
public class BeanSerializerWithValidation extends ValueSerializer<Object> {

private final BeanSerializerBase delegate;
private final Validator validator;
private final StrictnessMode strictnessMode;

@Override
public void serialize(Object bean, JsonGenerator gen, SerializationContext ctxt) throws JacksonException {
var violations = validator.validate(bean);
if (!violations.isEmpty()) {
throw new ConstraintViolationException(violations);
validate(bean);
delegate.serialize(bean, gen, ctxt);
}

private <T> void validate(T object) {
var violations = validator.validate(object);
if (violations.isEmpty()) {
return;
}

delegate.serialize(bean, gen, ctxt);
var exception = new ConstraintViolationException(violations);
switch (strictnessMode) {
case LogWarning -> log.warn("There are constraint violations", exception);
case ThrowError -> throw exception;
}
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package de.rwth.idsg.ocpp.jaxb.validation;

import lombok.Builder;
import tools.jackson.databind.module.SimpleModule;

import jakarta.validation.Validation;
Expand All @@ -10,30 +11,47 @@
*/
public class BeanValidationModule extends SimpleModule {

private BeanValidationModule(Validator validator, boolean forReading, boolean forWriting) {
@Builder
private BeanValidationModule(Validator validator, StrictnessMode readingMode, StrictnessMode writingMode) {
if (readingMode == null && writingMode == null) {
throw new NullPointerException("readingMode and writingMode are null");
}

Validator validatorToUse = validator == null
? Validation.buildDefaultValidatorFactory().getValidator()
: validator;

if (forReading) {
setDeserializerModifier(new BeanDeserializerModifierWithValidation(validatorToUse));
if (readingMode != null) {
setDeserializerModifier(new BeanDeserializerModifierWithValidation(validatorToUse, readingMode));
}

if (forWriting) {
setSerializerModifier(new BeanSerializerModifierWithValidation(validatorToUse));
if (writingMode != null) {
setSerializerModifier(new BeanSerializerModifierWithValidation(validatorToUse, writingMode));
}
}

public static BeanValidationModule forReading(Validator validator) {
return new BeanValidationModule(validator, true, false);
return BeanValidationModule.builder()
.validator(validator)
.readingMode(StrictnessMode.ThrowError)
.writingMode(null)
.build();
}

public static BeanValidationModule forWriting(Validator validator) {
return new BeanValidationModule(validator, false, true);
return BeanValidationModule.builder()
.validator(validator)
.readingMode(null)
.writingMode(StrictnessMode.ThrowError)
.build();
}

public static BeanValidationModule forReadingAndWriting(Validator validator) {
return new BeanValidationModule(validator, true, true);
return BeanValidationModule.builder()
.validator(validator)
.readingMode(StrictnessMode.ThrowError)
.writingMode(StrictnessMode.ThrowError)
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package de.rwth.idsg.ocpp.jaxb.validation;

public enum StrictnessMode {
LogWarning,
ThrowError
}
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.17</version>
<scope>compile</scope>
</dependency>

<!-- Jackson 3.x components rely on 2.x annotations; there are no separate 3.x jackson-annotations -->
<dependency>
Expand Down