001package ball.beans;
002/*-
003 * ##########################################################################
004 * Utilities
005 * $Id: PropertyMethodEnum.java 5881 2020-05-06 04:14:12Z ball $
006 * $HeadURL: svn+ssh://svn.hcf.dev/var/spool/scm/repository.svn/ball-util/trunk/src/main/java/ball/beans/PropertyMethodEnum.java $
007 * %%
008 * Copyright (C) 2008 - 2020 Allen D. Ball
009 * %%
010 * Licensed under the Apache License, Version 2.0 (the "License");
011 * you may not use this file except in compliance with the License.
012 * You may obtain a copy of the License at
013 *
014 *      http://www.apache.org/licenses/LICENSE-2.0
015 *
016 * Unless required by applicable law or agreed to in writing, software
017 * distributed under the License is distributed on an "AS IS" BASIS,
018 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
019 * See the License for the specific language governing permissions and
020 * limitations under the License.
021 * ##########################################################################
022 */
023import ball.annotation.ConstantValueMustConvertTo;
024import java.lang.reflect.Method;
025import java.util.Collections;
026import java.util.EnumMap;
027import java.util.Map;
028import java.util.regex.Matcher;
029import java.util.regex.Pattern;
030
031import static java.beans.Introspector.decapitalize;
032
033/**
034 * Bean property method {@link Enum} type.
035 *
036 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball}
037 * @version $Revision: 5881 $
038 */
039public enum PropertyMethodEnum {
040    GET, IS, SET;
041
042    private static final Map<PropertyMethodEnum,Method> MAP =
043        Collections.unmodifiableMap(new MethodPrototypeMap());
044
045    @ConstantValueMustConvertTo(value = Pattern.class, method = "compile")
046    private static final String PROPERTY_REGEX = "([\\p{Upper}][\\p{Alnum}]*)";
047
048    private Pattern pattern = null;
049
050    /**
051     * Method to get the prototype return type {@link Class} for this method
052     * type.
053     *
054     * @return  The return type {@link Class}.
055     */
056    public Class<?> getReturnType() { return MAP.get(this).getReturnType(); }
057
058    /**
059     * Method to get the prototype parameter types ({@link Class}es) for
060     * this method type.
061     *
062     * @return  The parameter types array (of {@link Class}es).
063     */
064    public Class<?>[] getParameterTypes() {
065        return MAP.get(this).getParameterTypes();
066    }
067
068    /**
069     * Method to get the property name from the argument method name.
070     *
071     * @param   method          The candidate getter/setter method name.
072     *
073     * @return  The property name if method name matches the pattern;
074     *          {@code null} if the argument is {@code null} or doesn't
075     *          match.
076     */
077    public String getPropertyName(String method) {
078        String name = null;
079
080        if (method != null) {
081            Matcher matcher = pattern().matcher(method);
082
083            if (matcher.matches()) {
084                name = decapitalize(matcher.group(1));
085            }
086        }
087
088        return name;
089    }
090
091    private Pattern pattern() {
092        if (pattern == null) {
093            pattern =
094                Pattern.compile(Pattern.quote(name().toLowerCase())
095                                + PROPERTY_REGEX);
096        }
097
098        return pattern;
099    }
100
101    /**
102     * Static method to get a property name from a {@link Method} name.
103     * (This method does not check return type or parameter types.)
104     *
105     * @param   method          The {@link Method}.
106     *
107     * @return  The property name if method name matches the pattern;
108     *          {@code null} if the argument is {@code null} or the name
109     *          doesn't match.
110     */
111    public static String getPropertyName(Method method) {
112        String name = null;
113
114        if (method != null) {
115            for (PropertyMethodEnum methodEnum : values()) {
116                name = methodEnum.getPropertyName(method.getName());
117
118                if (name != null) {
119                    break;
120                }
121            }
122        }
123
124        return name;
125    }
126
127    private static class MethodPrototypeMap
128                         extends EnumMap<PropertyMethodEnum,Method> {
129        private static final long serialVersionUID = 6408568606272721794L;
130
131        public MethodPrototypeMap() {
132            super(PropertyMethodEnum.class);
133
134            for (Method method : Prototypes.class.getDeclaredMethods()) {
135                put(PropertyMethodEnum.valueOf(method.getName()), method);
136            }
137        }
138
139        public interface Prototypes<T> {
140            public T GET();
141            public boolean IS();
142            public void SET(T value);
143        }
144    }
145}