Skip to content

Commit 26906fb

Browse files
DavideDmarko-bekhta
authored andcommitted
HV-1591 Test for deprecated use of Value annotation
A user must apply `@Value` to the argument(s) of a container type. If they don't, there should be message in the logs warning them. Signed-off-by: marko-bekhta <[email protected]>
1 parent 4a48748 commit 26906fb

File tree

1 file changed

+286
-0
lines changed

1 file changed

+286
-0
lines changed
Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.validator.test.constraints.annotations.hv;
6+
7+
import static org.assertj.core.api.Assertions.assertThat;
8+
9+
import java.util.List;
10+
import java.util.Map;
11+
import java.util.Set;
12+
13+
import jakarta.validation.Valid;
14+
import jakarta.validation.constraints.NotNull;
15+
16+
import org.hibernate.validator.internal.metadata.aggregated.CascadingMetaDataBuilder;
17+
import org.hibernate.validator.test.constraints.annotations.AbstractConstrainedTest;
18+
import org.hibernate.validator.test.internal.engine.serialization.Email;
19+
import org.hibernate.validator.testutils.ListAppender;
20+
21+
import org.apache.logging.log4j.Level;
22+
import org.apache.logging.log4j.core.Logger;
23+
import org.apache.logging.log4j.core.LoggerContext;
24+
import org.apache.logging.log4j.core.config.Configurator;
25+
import org.testng.annotations.AfterTest;
26+
import org.testng.annotations.BeforeMethod;
27+
import org.testng.annotations.BeforeTest;
28+
import org.testng.annotations.Test;
29+
30+
public class ValidAnnotationTest extends AbstractConstrainedTest {
31+
32+
private ListAppender logAppender;
33+
private Level originalLogLevel;
34+
private Logger targetLogger;
35+
36+
/**
37+
* @return true if the string matches the expected log message for deprecated use of @Value.
38+
*/
39+
private static boolean deprecatedUsedOfValueCode(String s) {
40+
return s.startsWith( "HV000271" );
41+
}
42+
43+
private static boolean potentiallyDeprecatedUsedOfValueCode(String s) {
44+
return s.startsWith( "HV000272" );
45+
}
46+
47+
@BeforeTest
48+
public void setUpLogger() {
49+
logAppender = new ListAppender( ValidAnnotationTest.class.getSimpleName() );
50+
logAppender.start();
51+
52+
LoggerContext context = LoggerContext.getContext( false );
53+
targetLogger = context.getLogger( CascadingMetaDataBuilder.class.getName() );
54+
targetLogger.addAppender( logAppender );
55+
56+
// Set level of log messages to WARN (if they are not already enabled)
57+
if ( targetLogger.getLevel().isMoreSpecificThan( Level.WARN ) ) {
58+
// Store the original log level to restore it later
59+
originalLogLevel = targetLogger.getLevel();
60+
61+
// Override the log level for this test class only
62+
// Default tests will only print the error messages, we need to override it
63+
// so that we can capture the deprecated warning message
64+
Configurator.setLevel( CascadingMetaDataBuilder.class.getName(), Level.WARN );
65+
context.updateLoggers();
66+
}
67+
}
68+
69+
@BeforeMethod
70+
public void cleanLogger() {
71+
logAppender.clear();
72+
}
73+
74+
@AfterTest
75+
public void tearDownLogger() {
76+
targetLogger.removeAppender( logAppender );
77+
logAppender.stop();
78+
79+
// Restore the original log level
80+
if ( originalLogLevel != null ) {
81+
Configurator.setLevel( CascadingMetaDataBuilder.class.getName(), originalLogLevel );
82+
// Update the logger context to apply changes
83+
LoggerContext context = LoggerContext.getContext( false );
84+
context.updateLoggers();
85+
}
86+
}
87+
88+
@Test
89+
public void twiceWithList() {
90+
class Foo {
91+
92+
@Valid
93+
private List<@Valid String> prop;
94+
95+
public Foo(List<String> prop) {
96+
this.prop = prop;
97+
}
98+
}
99+
100+
Foo foo = new Foo( List.of( "K1" ) );
101+
validator.validate( foo );
102+
103+
assertThat( logAppender.getMessages() ).hasSize( 1 ).allMatch( ValidAnnotationTest::deprecatedUsedOfValueCode );
104+
}
105+
106+
@Test
107+
public void onTheContainerWithList() {
108+
class Foo {
109+
110+
@Valid
111+
private List<MyBean> prop;
112+
113+
public Foo(List<MyBean> prop) {
114+
this.prop = prop;
115+
}
116+
}
117+
118+
Foo foo = new Foo( List.of( new MyBean( "[email protected]" ) ) );
119+
validator.validate( foo );
120+
121+
assertThat( logAppender.getMessages() ).hasSize( 1 ).allMatch( ValidAnnotationTest::deprecatedUsedOfValueCode );
122+
}
123+
124+
@Test
125+
public void twiceWithSet() {
126+
class Foo {
127+
128+
@Valid
129+
private Set<@Valid String> prop;
130+
131+
public Foo(Set<String> prop) {
132+
this.prop = prop;
133+
}
134+
}
135+
136+
Foo foo = new Foo( Set.of( "K1" ) );
137+
validator.validate( foo );
138+
139+
assertThat( logAppender.getMessages() ).hasSize( 1 ).allMatch( ValidAnnotationTest::deprecatedUsedOfValueCode );
140+
}
141+
142+
@Test
143+
public void onTheContainerWithSet() {
144+
class Foo {
145+
146+
@Valid
147+
private Set<MyBean> prop;
148+
149+
public Foo(Set<MyBean> prop) {
150+
this.prop = prop;
151+
}
152+
}
153+
154+
Foo foo = new Foo( Set.of( new MyBean( "[email protected]" ) ) );
155+
validator.validate( foo );
156+
157+
assertThat( logAppender.getMessages() ).hasSize( 1 ).allMatch( ValidAnnotationTest::deprecatedUsedOfValueCode );
158+
}
159+
160+
@Test
161+
public void twiceWithMap() {
162+
class Foo {
163+
164+
@Valid
165+
private Map<String, @Valid String> prop;
166+
167+
public Foo(Map<String, String> prop) {
168+
this.prop = prop;
169+
}
170+
}
171+
172+
Foo foo = new Foo( Map.of( "K1", "V1" ) );
173+
validator.validate( foo );
174+
175+
assertThat( logAppender.getMessages() ).hasSize( 1 ).allMatch( ValidAnnotationTest::deprecatedUsedOfValueCode );
176+
}
177+
178+
@Test
179+
public void onContainerWithMap() {
180+
class Foo {
181+
182+
@Valid
183+
private Map<String, MyBean> prop;
184+
185+
public Foo(Map<String, MyBean> prop) {
186+
this.prop = prop;
187+
}
188+
}
189+
190+
Foo foo = new Foo( Map.of( "K1", new MyBean( "[email protected]" ) ) );
191+
validator.validate( foo );
192+
193+
assertThat( logAppender.getMessages() ).hasSize( 1 ).allMatch( ValidAnnotationTest::deprecatedUsedOfValueCode );
194+
}
195+
196+
private static class MyBean {
197+
@Email
198+
private String email;
199+
200+
public MyBean(String email) {
201+
this.email = email;
202+
}
203+
204+
public String getEmail() {
205+
return email;
206+
}
207+
208+
public void setEmail(String email) {
209+
this.email = email;
210+
}
211+
}
212+
213+
@Test
214+
public void onGetter() {
215+
class Foo {
216+
217+
private List<String> prop;
218+
219+
public Foo(List<String> prop) {
220+
this.prop = prop;
221+
}
222+
223+
public @Valid List<String> getProp() {
224+
return prop;
225+
}
226+
}
227+
228+
Foo foo = new Foo( List.of( "K1" ) );
229+
validator.validate( foo );
230+
231+
// getter is processed as a property an as an executable so there will be 2 warnings:
232+
assertThat( logAppender.getMessages() ).hasSize( 2 ).allMatch( ValidAnnotationTest::deprecatedUsedOfValueCode );
233+
}
234+
235+
@Test
236+
public void onReturnValue() throws NoSuchMethodException {
237+
class Bar {
238+
private @NotNull String prop;
239+
}
240+
class Foo {
241+
public @Valid List<Bar> something() {
242+
return null;
243+
}
244+
}
245+
246+
Foo foo = new Foo();
247+
validator.forExecutables().validateReturnValue(
248+
foo,
249+
Foo.class.getMethod( "something" ),
250+
List.of( new Bar() )
251+
);
252+
253+
assertThat( logAppender.getMessages() ).hasSize( 1 ).allMatch( ValidAnnotationTest::deprecatedUsedOfValueCode );
254+
}
255+
256+
@Test
257+
public void onParameter() throws NoSuchMethodException {
258+
class Bar {
259+
private @NotNull String prop;
260+
}
261+
class Foo {
262+
public void something(@Valid List<Bar> bars) {
263+
}
264+
}
265+
266+
Foo foo = new Foo();
267+
validator.forExecutables().validateParameters(
268+
foo,
269+
Foo.class.getMethod( "something", List.class ),
270+
new Object[] { List.of( new Bar() ) }
271+
);
272+
273+
assertThat( logAppender.getMessages() ).hasSize( 1 ).allMatch( ValidAnnotationTest::deprecatedUsedOfValueCode );
274+
}
275+
276+
@Test
277+
public void onPotentiallyCascadable() throws NoSuchMethodException {
278+
class Foo {
279+
private @Valid Object prop;
280+
}
281+
282+
validator.validate( new Foo() );
283+
284+
assertThat( logAppender.getMessages() ).hasSize( 1 ).allMatch( ValidAnnotationTest::potentiallyDeprecatedUsedOfValueCode );
285+
}
286+
}

0 commit comments

Comments
 (0)