001package ball.util; 002/*- 003 * ########################################################################## 004 * Utilities 005 * $Id: PatternMatcherBean.java 5285 2020-02-05 04:23:21Z ball $ 006 * $HeadURL: svn+ssh://svn.hcf.dev/var/spool/scm/repository.svn/ball-util/trunk/src/main/java/ball/util/PatternMatcherBean.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.MatcherGroup; 024import ball.annotation.PatternRegex; 025import java.lang.annotation.AnnotationFormatError; 026import java.lang.reflect.Field; 027import java.lang.reflect.Method; 028import java.util.List; 029import java.util.regex.Matcher; 030import java.util.regex.Pattern; 031import org.apache.commons.lang3.reflect.FieldUtils; 032import org.apache.commons.lang3.reflect.MethodUtils; 033 034import static ball.util.Converter.convertTo; 035 036/** 037 * Interface providing default methods for beans classes annotated with 038 * {@link PatternRegex} and whose methods are annotated with 039 * {@link MatcherGroup}. 040 * 041 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball} 042 * @version $Revision: 5285 $ 043 */ 044public interface PatternMatcherBean { 045 046 /** 047 * Method to initialize fields and methods annotated with 048 * {@link MatcherGroup} with the results of parsing the {@code sequence} 049 * argument. 050 * 051 * @param sequence The {@link CharSequence} to parse. 052 * 053 * @throws IllegalArgumentException 054 * If the {@link CharSequence} does not match 055 * the {@link PatternRegex#value()}. 056 */ 057 default void initialize(CharSequence sequence) { 058 Matcher matcher = matcher(sequence); 059 060 if (! matcher.matches()) { 061 throw new IllegalArgumentException("\"" + String.valueOf(sequence) 062 + "\" does not match " 063 + matcher.pattern().pattern()); 064 } 065 066 try { 067 List<Field> fields = 068 FieldUtils.getFieldsListWithAnnotation(getClass(), 069 MatcherGroup.class); 070 071 for (Field field : fields) { 072 MatcherGroup group = field.getAnnotation(MatcherGroup.class); 073 String string = matcher.group(group.value()); 074 Object value = 075 (string != null) 076 ? convertTo(string, field.getType()) 077 : null; 078 079 FieldUtils.writeField(field, this, value, true); 080 } 081 082 List<Method> methods = 083 MethodUtils.getMethodsListWithAnnotation(getClass(), 084 MatcherGroup.class, 085 true, true); 086 087 for (Method method : methods) { 088 MatcherGroup group = method.getAnnotation(MatcherGroup.class); 089 Object value = 090 convertTo(matcher.group(group.value()), 091 method.getParameterTypes()[0]); 092 093 MethodUtils.invokeMethod(this, true, 094 method.getName(), 095 new Object[] { value }, 096 method.getParameterTypes()); 097 } 098 } catch (IllegalAccessException exception) { 099 exception.printStackTrace(System.err); 100 } catch (RuntimeException exception) { 101 throw exception; 102 } catch (Exception exception) { 103 throw new IllegalArgumentException(String.valueOf(matcher), 104 exception); 105 } 106 } 107 108 /** 109 * Method to get the {@link Matcher} for the argument input. 110 * 111 * @param sequence The {@link CharSequence} to parse. 112 * 113 * @return The {@link Matcher} for the {@link #pattern()} applied to 114 * the {@link CharSequence}. 115 */ 116 default Matcher matcher(CharSequence sequence) { 117 return pattern().matcher(sequence); 118 } 119 120 /** 121 * Method to get the compiled {@link Pattern} for this annotated bean. 122 * 123 * @return The {@link Pattern}. 124 */ 125 default Pattern pattern() { 126 Pattern pattern = null; 127 PatternRegex annotation = getClass().getAnnotation(PatternRegex.class); 128 129 try { 130 pattern = Pattern.compile(annotation.value()); 131 } catch (Exception exception) { 132 throw new AnnotationFormatError(annotation.toString(), exception); 133 } 134 135 return pattern; 136 } 137}