We're updating the issue view to help you get more done. 

Validation of Java 8 Optional throws ClassCastException

Description

validation of nested Optional object throws class cast exception, if the getter is Optional but field

for example: following code ends with class cast exception:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 private class X { @Valid private Y y; public void setY(Y y) { this.y = y; } public Optional<Y> getY() { return Optional.ofNullable(y); } } private class Y { @Valid private Z z; public void setZ(Z z) { this.z = z; } public Optional<Z> z() { return Optional.ofNullable(z); } } private class Z { @NotNull private String karel; @NotNull(groups = Group1.class) private String johny; @NotNull private Integer test; public String getKarel() { return karel; } public void setKarel(String karel) { this.karel = karel; } public String getJohny() { return johny; } public void setJohny(String johny) { this.johny = johny; } public Optional<Integer> getTest() { return null; } } private interface Group1 { } private ValidationService validationService = validationService(); private ValidationService validationService() { ValidationServiceImpl service = new ValidationServiceImpl(); return service; } @Test public void test_1() { X x = new X(); x.y = new Y(); x.y.z = new Z(); x.y.z.test = 1; Assert.assertEquals(2, validationService.getConstraintViolations(x, Group1.class).size()); }

The problem is that code tries to unwrap that Optional without checking, if the original field value is really Optional (it probably checks only getter)

Workaround exist

if you explicitly change your classes to "do not unwrap", the validation is successfully finished but I would expected that it should work in this way automatically without that annotation.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 private class X { @Valid @UnwrapValidatedValue(false) private Y y; public void setY(Y y) { this.y = y; } public Optional<Y> getY() { return Optional.ofNullable(y); } } private class Y { @Valid @UnwrapValidatedValue(false) private Z z; public void setZ(Z z) { this.z = z; } public Optional<Z> z() { return Optional.ofNullable(z); } } private class Z { @NotNull private String karel; @NotNull(groups = Group1.class) private String johny; @NotNull @UnwrapValidatedValue(false) private Integer test; public String getKarel() { return karel; } public void setKarel(String karel) { this.karel = karel; } public String getJohny() { return johny; } public void setJohny(String johny) { this.johny = johny; } public Optional<Integer> getTest() { return null; } } private interface Group1 { } private ValidationService validationService = validationService(); private ValidationService validationService() { ValidationServiceImpl service = new ValidationServiceImpl(); return service; } @Test public void test_1() { X x = new X(); x.y = new Y(); x.y.z = new Z(); x.y.z.test = 1; Assert.assertEquals(2, validationService.getConstraintViolations(x, Group1.class).size()); }

Environment

None

Status

Assignee

Gunnar Morling

Reporter

Jaroslav Strouhal

Labels

None

Worked in

None

Feedback Requested

None

Feedback Requested By

None

backPortable

None

Community Help Wanted

None

Suitable for new contributors

None

Requires Release Note

None

backportDecision

None

backportReEvaluate

None

Components

Fix versions

Affects versions

5.2.4.Final

Priority

Major