1 /*
2  * Hibernate Validator, declare and validate application constraints
3  *
4  * License: Apache License, Version 2.0
5  * See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
6  */

7 package org.hibernate.validator.internal.properties;
8
9 import java.lang.invoke.MethodHandles;
10 import java.util.Optional;
11 import java.util.Set;
12
13 import org.hibernate.validator.internal.util.CollectionHelper;
14 import org.hibernate.validator.internal.util.Contracts;
15 import org.hibernate.validator.internal.util.StringHelper;
16 import org.hibernate.validator.internal.util.logging.Log;
17 import org.hibernate.validator.internal.util.logging.LoggerFactory;
18 import org.hibernate.validator.spi.properties.ConstrainableExecutable;
19 import org.hibernate.validator.spi.properties.GetterPropertySelectionStrategy;
20
21 /**
22  * @author Marko Bekhta
23  */

24 public class DefaultGetterPropertySelectionStrategy implements GetterPropertySelectionStrategy {
25
26     private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() );
27
28     private static final String GETTER_PREFIX_GET = "get";
29     private static final String GETTER_PREFIX_IS = "is";
30     private static final String GETTER_PREFIX_HAS = "has";
31     private static final String[] GETTER_PREFIXES = {
32             GETTER_PREFIX_GET,
33             GETTER_PREFIX_IS,
34             GETTER_PREFIX_HAS
35     };
36
37     @Override
38     public Optional<String> getProperty(ConstrainableExecutable executable) {
39         Contracts.assertNotNull( executable, "executable cannot be null" );
40
41         if ( !isGetter( executable ) ) {
42             return Optional.empty();
43         }
44
45         String methodName = executable.getName();
46
47         for ( String prefix : GETTER_PREFIXES ) {
48             if ( methodName.startsWith( prefix ) ) {
49                 return Optional.of( StringHelper.decapitalize( methodName.substring( prefix.length() ) ) );
50             }
51         }
52
53         throw new AssertionError( "Method " + executable.getName() + " was considered a getter but we couldn't extract a property name." );
54     }
55
56     @Override
57     public Set<String> getGetterMethodNameCandidates(String propertyName) {
58         Contracts.assertNotEmpty( propertyName, "Name of a property must not be empty" );
59
60         Set<String> nameCandidates = CollectionHelper.newHashSet( GETTER_PREFIXES.length );
61         for ( String prefix : GETTER_PREFIXES ) {
62             nameCandidates.add( prefix + Character.toUpperCase( propertyName.charAt( 0 ) ) + propertyName.substring( 1 ) );
63         }
64         return nameCandidates;
65     }
66
67     /**
68      * Checks whether the given executable is a valid JavaBean getter method, which
69      * is the case if
70      * <ul>
71      * <li>its name starts with "get" and it has a return type but no parameter or</li>
72      * <li>its name starts with "is", it has no parameter and is returning
73      * {@code boolean} or</li>
74      * <li>its name starts with "has", it has no parameter and is returning
75      * {@code boolean} (HV-specific, not mandated by the JavaBeans spec).</li>
76      * </ul>
77      *
78      * @param executable The executable of interest.
79      *
80      * @return {@code true}, if the given executable is a JavaBean getter method,
81      * {@code false} otherwise.
82      */

83     private static boolean isGetter(ConstrainableExecutable executable) {
84         if ( executable.getParameterTypes().length != 0 ) {
85             return false;
86         }
87
88         String methodName = executable.getName();
89
90         //<PropertyType> get<PropertyName>()
91         if ( methodName.startsWith( GETTER_PREFIX_GET ) && executable.getReturnType() != void.class ) {
92             return true;
93         }
94         //boolean is<PropertyName>()
95         else if ( methodName.startsWith( GETTER_PREFIX_IS ) && executable.getReturnType() == boolean.class ) {
96             return true;
97         }
98         //boolean has<PropertyName>()
99         else if ( methodName.startsWith( GETTER_PREFIX_HAS ) && executable.getReturnType() == boolean.class ) {
100             return true;
101         }
102
103         return false;
104     }
105 }
106