Skip to content

Commit 5cb6a2f

Browse files
authored
Fix NPE when cascade @Valid on nullable pojo (#271)
When cascading via @Valid on a related pojo that can be nullable, this can generate an NPE. Fix is to change the generated code for pojo adapters to check for the value/pojo to be null and skip the validation in that case
1 parent c26a2d3 commit 5cb6a2f

File tree

4 files changed

+96
-1
lines changed

4 files changed

+96
-1
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package example.avaje.cascade;
2+
3+
import io.avaje.validation.constraints.NotBlank;
4+
import io.avaje.validation.constraints.Size;
5+
import io.avaje.validation.constraints.Valid;
6+
7+
@Valid
8+
public class MAddress {
9+
10+
@NotBlank @Size(max = 10)
11+
public String line1;
12+
public String line2;
13+
14+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package example.avaje.cascade;
2+
3+
import io.avaje.validation.constraints.NotBlank;
4+
import io.avaje.validation.constraints.NotNull;
5+
import io.avaje.validation.constraints.Valid;
6+
7+
import java.time.LocalDate;
8+
9+
@Valid
10+
public class MCustomer {
11+
12+
boolean active;
13+
14+
@NotBlank(max = 20)
15+
String name;
16+
17+
@NotNull
18+
LocalDate activeDate;
19+
20+
@Valid
21+
MAddress billingAddress;
22+
23+
public MCustomer setActive(boolean active) {
24+
this.active = active;
25+
return this;
26+
}
27+
28+
public MCustomer setName(String name) {
29+
this.name = name;
30+
return this;
31+
}
32+
33+
public MCustomer setActiveDate(LocalDate activeDate) {
34+
this.activeDate = activeDate;
35+
return this;
36+
}
37+
38+
public MCustomer setBillingAddress(MAddress billingAddress) {
39+
this.billingAddress = billingAddress;
40+
return this;
41+
}
42+
43+
public boolean active() {
44+
return active;
45+
}
46+
47+
public String name() {
48+
return name;
49+
}
50+
51+
public LocalDate activeDate() {
52+
return activeDate;
53+
}
54+
55+
public MAddress billingAddress() {
56+
return billingAddress;
57+
}
58+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package example.avaje.cascade;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import org.junit.jupiter.api.Test;
6+
import io.avaje.validation.Validator;
7+
8+
import java.time.LocalDate;
9+
10+
class MCustomerTest {
11+
12+
Validator validator = Validator.builder().build();
13+
14+
@Test
15+
void valid() {
16+
var customer = new MCustomer()
17+
.setName("Foo")
18+
.setActiveDate(LocalDate.now())
19+
.setActive(true);
20+
21+
validator.validate(customer);
22+
}
23+
}

validator-generator/src/main/java/io/avaje/validation/generator/ClassReader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ public void cascadeTypes(Set<String> types) {
106106

107107
@Override
108108
public void writeFields(Append writer) {
109-
110109
for (final FieldReader allField : allFields) {
111110
allField.writeField(writer);
112111
}
@@ -125,6 +124,7 @@ public void writeValidatorMethod(Append writer) {
125124
writer.eol();
126125
writer.append(" @Override").eol();
127126
writer.append(" public boolean validate(%s value, ValidationRequest request, String field) {", shortName).eol();
127+
writer.append(" if (value == null) return true; // continue validation").eol();
128128
writer.append(" if (field != null) {").eol();
129129
writer.append(" request.pushPath(field);").eol();
130130
writer.append(" }").eol();

0 commit comments

Comments
 (0)