Skip to content
This repository was archived by the owner on May 28, 2018. It is now read-only.

Commit 827dce1

Browse files
author
Michal Gajdos
committed
JERSEY-2499: Bean validation not working for constraints placed on super classes
- fix + test Change-Id: I11ed64c6417ec5f96a6f37a6145b78a2f7212ad0 Signed-off-by: Michal Gajdos <[email protected]>
1 parent 8074c34 commit 827dce1

File tree

2 files changed

+221
-16
lines changed

2 files changed

+221
-16
lines changed

ext/bean-validation/src/main/java/org/glassfish/jersey/server/validation/internal/ValidateOnExecutionTraversableResolver.java

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@
4141
package org.glassfish.jersey.server.validation.internal;
4242

4343
import java.lang.annotation.ElementType;
44+
import java.lang.reflect.Field;
4445
import java.lang.reflect.Method;
4546
import java.security.AccessController;
46-
import java.security.PrivilegedAction;
4747
import java.util.concurrent.ConcurrentMap;
4848

4949
import javax.validation.Path;
@@ -99,7 +99,11 @@ public boolean isReachable(final Object traversableObject,
9999
final String propertyKey = traversableObjectClass.getName() + "#" + propertyName;
100100

101101
if (!propertyToMethod.containsKey(propertyKey)) {
102-
propertyToMethod.putIfAbsent(propertyKey, getGetterMethod(traversableObjectClass, propertyName));
102+
final Method getter = getGetterMethod(traversableObjectClass, propertyName);
103+
104+
if (getter != null) {
105+
propertyToMethod.putIfAbsent(propertyKey, getter);
106+
}
103107
}
104108

105109
final Method getter = propertyToMethod.get(propertyKey);
@@ -127,20 +131,12 @@ public boolean isCascadable(final Object traversableObject,
127131
*/
128132
private Method getGetterMethod(final Class<?> clazz, final String propertyName) {
129133
// Property type.
130-
final Class<?> propertyType = AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
131-
132-
@Override
133-
public Class<?> run() {
134-
try {
135-
return clazz.getDeclaredField(propertyName).getType();
136-
} catch (SecurityException ex) {
137-
// NOOP.
138-
} catch (NoSuchFieldException nsfe) {
139-
// NOOP.
140-
}
141-
return null;
134+
Class<?> propertyType = null;
135+
for (final Field field : AccessController.doPrivileged(ReflectionHelper.getAllFieldsPA(clazz))) {
136+
if (field.getName().equals(propertyName)) {
137+
propertyType = field.getType();
142138
}
143-
});
139+
}
144140

145141
final char[] chars = propertyName.toCharArray();
146142
chars[0] = Character.toUpperCase(chars[0]);
@@ -149,7 +145,7 @@ public Class<?> run() {
149145
final String isGetter = "is" + getterPropertyName;
150146
final String getGetter = "get" + getterPropertyName;
151147

152-
for (final Method method : AccessController.doPrivileged(ReflectionHelper.getDeclaredMethodsPA(clazz))) {
148+
for (final Method method : AccessController.doPrivileged(ReflectionHelper.getMethodsPA(clazz))) {
153149
final String methodName = method.getName();
154150

155151
if ((methodName.equals(isGetter) || methodName.equals(getGetter))
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
/*
2+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3+
*
4+
* Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
5+
*
6+
* The contents of this file are subject to the terms of either the GNU
7+
* General Public License Version 2 only ("GPL") or the Common Development
8+
* and Distribution License("CDDL") (collectively, the "License"). You
9+
* may not use this file except in compliance with the License. You can
10+
* obtain a copy of the License at
11+
* http://glassfish.java.net/public/CDDL+GPL_1_1.html
12+
* or packager/legal/LICENSE.txt. See the License for the specific
13+
* language governing permissions and limitations under the License.
14+
*
15+
* When distributing the software, include this License Header Notice in each
16+
* file and include the License file at packager/legal/LICENSE.txt.
17+
*
18+
* GPL Classpath Exception:
19+
* Oracle designates this particular file as subject to the "Classpath"
20+
* exception as provided by Oracle in the GPL Version 2 section of the License
21+
* file that accompanied this code.
22+
*
23+
* Modifications:
24+
* If applicable, add the following below the License Header, with the fields
25+
* enclosed by brackets [] replaced by your own identifying information:
26+
* "Portions Copyright [year] [name of copyright owner]"
27+
*
28+
* Contributor(s):
29+
* If you wish your version of this file to be governed by only the CDDL or
30+
* only the GPL Version 2, indicate your decision by adding "[Contributor]
31+
* elects to include this software in this distribution under the [CDDL or GPL
32+
* Version 2] license." If you don't indicate a single choice of license, a
33+
* recipient has the option to distribute your version of this file under
34+
* either the CDDL, the GPL Version 2 or to extend the choice of license to
35+
* its licensees as provided above. However, if you add GPL Version 2 code
36+
* and therefore, elected the GPL Version 2 license, then the option applies
37+
* only if the new code is made subject to such option by the copyright
38+
* holder.
39+
*/
40+
41+
package org.glassfish.jersey.tests.e2e.server.validation;
42+
43+
import javax.ws.rs.POST;
44+
import javax.ws.rs.Path;
45+
import javax.ws.rs.core.Application;
46+
import javax.ws.rs.core.Response;
47+
48+
import javax.validation.Valid;
49+
import javax.validation.constraints.Max;
50+
import javax.validation.constraints.Min;
51+
import javax.validation.constraints.NotNull;
52+
53+
import org.glassfish.jersey.client.ClientConfig;
54+
import org.glassfish.jersey.jackson.JacksonFeature;
55+
import org.glassfish.jersey.server.ResourceConfig;
56+
import org.glassfish.jersey.test.JerseyTest;
57+
58+
import org.hibernate.validator.constraints.NotBlank;
59+
import org.junit.Test;
60+
import static org.hamcrest.CoreMatchers.is;
61+
import static org.hamcrest.MatcherAssert.assertThat;
62+
63+
/**
64+
* Tests to ensure that validation constraints on a superclass are validated as well.
65+
*
66+
* @author Michal Gajdos (michal.gajdos at oracle.com)
67+
*/
68+
public class EntityInheritanceValidationTest extends JerseyTest {
69+
70+
@Path("/")
71+
public static class Resource {
72+
73+
@POST
74+
public Entity post(@Valid final Entity entity) {
75+
return entity;
76+
}
77+
}
78+
79+
public static class AbstractEntity {
80+
81+
private String text;
82+
83+
public AbstractEntity() {
84+
}
85+
86+
public AbstractEntity(final String text) {
87+
this.text = text;
88+
}
89+
90+
@NotNull
91+
@NotBlank
92+
public String getText() {
93+
return text;
94+
}
95+
96+
public void setText(final String text) {
97+
this.text = text;
98+
}
99+
100+
@Override
101+
public boolean equals(final Object o) {
102+
if (this == o) {
103+
return true;
104+
}
105+
if (o == null || getClass() != o.getClass()) {
106+
return false;
107+
}
108+
109+
final AbstractEntity that = (AbstractEntity) o;
110+
111+
if (!text.equals(that.text)) {
112+
return false;
113+
}
114+
115+
return true;
116+
}
117+
118+
@Override
119+
public int hashCode() {
120+
return text.hashCode();
121+
}
122+
}
123+
124+
public static class Entity extends AbstractEntity {
125+
126+
private Integer number;
127+
128+
public Entity() {
129+
}
130+
131+
public Entity(final String text, final Integer number) {
132+
super(text);
133+
this.number = number;
134+
}
135+
136+
@Min(12)
137+
@Max(14)
138+
@NotNull
139+
public Integer getNumber() {
140+
return number;
141+
}
142+
143+
public void setNumber(final Integer number) {
144+
this.number = number;
145+
}
146+
147+
@Override
148+
public boolean equals(final Object o) {
149+
if (this == o) {
150+
return true;
151+
}
152+
if (o == null || getClass() != o.getClass()) {
153+
return false;
154+
}
155+
if (!super.equals(o)) {
156+
return false;
157+
}
158+
159+
final Entity entity = (Entity) o;
160+
161+
if (!number.equals(entity.number)) {
162+
return false;
163+
}
164+
165+
return true;
166+
}
167+
168+
@Override
169+
public int hashCode() {
170+
int result = super.hashCode();
171+
result = 31 * result + number.hashCode();
172+
return result;
173+
}
174+
}
175+
176+
@Override
177+
protected Application configure() {
178+
return new ResourceConfig(Resource.class)
179+
.register(JacksonFeature.class);
180+
}
181+
182+
@Override
183+
protected void configureClient(final ClientConfig config) {
184+
config.register(JacksonFeature.class);
185+
}
186+
187+
@Test
188+
public void testEntityInheritance() throws Exception {
189+
final Entity entity = new Entity("foo", 13);
190+
final Response response = target().request().post(javax.ws.rs.client.Entity.json(entity));
191+
192+
assertThat(response.getStatus(), is(200));
193+
assertThat(response.readEntity(Entity.class), is(entity));
194+
}
195+
196+
@Test
197+
public void testEntityInheritanceBlankText() throws Exception {
198+
final Response response = target().request().post(javax.ws.rs.client.Entity.json(new Entity("", 13)));
199+
200+
assertThat(response.getStatus(), is(400));
201+
}
202+
203+
@Test
204+
public void testEntityInheritanceInvalidNumber() throws Exception {
205+
final Response response = target().request().post(javax.ws.rs.client.Entity.json(new Entity("foo", 23)));
206+
207+
assertThat(response.getStatus(), is(400));
208+
}
209+
}

0 commit comments

Comments
 (0)