1
7 package org.hibernate.validator.internal.properties.javabean;
8
9 import static org.hibernate.validator.internal.util.logging.Messages.MESSAGES;
10
11 import java.lang.reflect.Constructor;
12 import java.lang.reflect.Executable;
13 import java.lang.reflect.Field;
14 import java.lang.reflect.Method;
15 import java.security.AccessController;
16 import java.security.PrivilegedAction;
17 import java.util.Optional;
18
19 import org.hibernate.validator.internal.properties.Constrainable;
20 import org.hibernate.validator.internal.util.Contracts;
21 import org.hibernate.validator.internal.util.privilegedactions.GetDeclaredConstructor;
22 import org.hibernate.validator.internal.util.privilegedactions.GetDeclaredField;
23 import org.hibernate.validator.internal.util.privilegedactions.GetDeclaredMethod;
24 import org.hibernate.validator.internal.util.privilegedactions.GetMethodFromGetterNameCandidates;
25 import org.hibernate.validator.spi.nodenameprovider.JavaBeanProperty;
26 import org.hibernate.validator.spi.nodenameprovider.PropertyNodeNameProvider;
27 import org.hibernate.validator.spi.properties.ConstrainableExecutable;
28 import org.hibernate.validator.spi.properties.GetterPropertySelectionStrategy;
29
30
36 public class JavaBeanHelper {
37
38 private final GetterPropertySelectionStrategy getterPropertySelectionStrategy;
39 private final PropertyNodeNameProvider propertyNodeNameProvider;
40
41 public JavaBeanHelper(GetterPropertySelectionStrategy getterPropertySelectionStrategy, PropertyNodeNameProvider propertyNodeNameProvider) {
42 this.getterPropertySelectionStrategy = getterPropertySelectionStrategy;
43 this.propertyNodeNameProvider = propertyNodeNameProvider;
44 }
45
46 public GetterPropertySelectionStrategy getGetterPropertySelectionStrategy() {
47 return getterPropertySelectionStrategy;
48 }
49
50 public Optional<JavaBeanField> findDeclaredField(Class<?> declaringClass, String property) {
51 Contracts.assertNotNull( declaringClass, MESSAGES.classCannotBeNull() );
52
53 Field field = run( GetDeclaredField.action( declaringClass, property ) );
54
55 return Optional.ofNullable( field ).map( this::field );
56 }
57
58 public Optional<JavaBeanGetter> findDeclaredGetter(Class<?> declaringClass, String property) {
59 Contracts.assertNotNull( declaringClass, MESSAGES.classCannotBeNull() );
60
61 return findGetter( declaringClass, property, false );
62 }
63
64 public Optional<JavaBeanGetter> findGetter(Class<?> declaringClass, String property) {
65 Contracts.assertNotNull( declaringClass, MESSAGES.classCannotBeNull() );
66
67 return findGetter( declaringClass, property, true );
68 }
69
70 private Optional<JavaBeanGetter> findGetter(Class<?> declaringClass, String property, boolean lookForMethodsOnSuperClass) {
71 Method getter = run(
72 GetMethodFromGetterNameCandidates.action(
73 declaringClass,
74 getterPropertySelectionStrategy.getGetterMethodNameCandidates( property ),
75 lookForMethodsOnSuperClass
76 )
77 );
78 if ( getter == null ) {
79 return Optional.empty();
80 }
81 else {
82 return Optional.of( new JavaBeanGetter( declaringClass, getter, property, propertyNodeNameProvider.getName(
83 new JavaBeanPropertyImpl( declaringClass, property ) ) ) );
84 }
85 }
86
87 public Optional<JavaBeanMethod> findDeclaredMethod(Class<?> declaringClass, String methodName, Class<?>... parameterTypes) {
88 Method method = run( GetDeclaredMethod.action( declaringClass, methodName, parameterTypes ) );
89 if ( method == null ) {
90 return Optional.empty();
91 }
92 else {
93 return Optional.of( executable( declaringClass, method ) );
94 }
95 }
96
97 public <T> Optional<JavaBeanConstructor> findDeclaredConstructor(Class<T> declaringClass, Class<?>... parameterTypes) {
98 Constructor<T> constructor = run( GetDeclaredConstructor.action( declaringClass, parameterTypes ) );
99 if ( constructor == null ) {
100 return Optional.empty();
101 }
102 else {
103 return Optional.of( new JavaBeanConstructor( constructor ) );
104 }
105 }
106
107 public JavaBeanExecutable<?> executable(Executable executable) {
108 return executable( executable.getDeclaringClass(), executable );
109 }
110
111 public JavaBeanExecutable<?> executable(Class<?> declaringClass, Executable executable) {
112 if ( executable instanceof Constructor ) {
113 return new JavaBeanConstructor( (Constructor<?>) executable );
114 }
115
116 return executable( declaringClass, ( (Method) executable ) );
117 }
118
119 public JavaBeanMethod executable(Class<?> declaringClass, Method method) {
120 JavaBeanConstrainableExecutable executable = new JavaBeanConstrainableExecutable( method );
121
122 Optional<String> correspondingProperty = getterPropertySelectionStrategy.getProperty( executable );
123 if ( correspondingProperty.isPresent() ) {
124 return new JavaBeanGetter( declaringClass, method, correspondingProperty.get(), propertyNodeNameProvider.getName(
125 new JavaBeanPropertyImpl( declaringClass, correspondingProperty.get() ) ) );
126 }
127
128 return new JavaBeanMethod( method );
129 }
130
131 public JavaBeanField field(Field field) {
132 return new JavaBeanField( field, propertyNodeNameProvider.getName( new JavaBeanPropertyImpl( field.getDeclaringClass(), field.getName() ) ) );
133 }
134
135
141 private <T> T run(PrivilegedAction<T> action) {
142 return System.getSecurityManager() != null ? AccessController.doPrivileged( action ) : action.run();
143 }
144
145 private static class JavaBeanConstrainableExecutable implements ConstrainableExecutable {
146
147 private final Method method;
148
149 private JavaBeanConstrainableExecutable(Method method) {
150 this.method = method;
151 }
152
153 @Override
154 public Class<?> getReturnType() {
155 return method.getReturnType();
156 }
157
158 @Override
159 public String getName() {
160 return method.getName();
161 }
162
163 @Override
164 public Class<?>[] getParameterTypes() {
165 return method.getParameterTypes();
166 }
167 }
168
169 private static class JavaBeanPropertyImpl implements JavaBeanProperty {
170 private final Class<?> declaringClass;
171 private final String name;
172
173 private JavaBeanPropertyImpl(Class<?> declaringClass, String name) {
174 this.declaringClass = declaringClass;
175 this.name = name;
176 }
177
178 @Override
179 public Class<?> getDeclaringClass() {
180 return declaringClass;
181 }
182
183 @Override
184 public String getName() {
185 return name;
186 }
187 }
188 }
189