Java tutorial
/****************************************************************************** * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for * the specific language governing rights and limitations under the License. * * The Original Code is: Jsoda * The Initial Developer of the Original Code is: William Wong (williamw520@gmail.com) * Portions created by William Wong are Copyright (C) 2012 William Wong, All Rights Reserved. * ******************************************************************************/ package wwutil.model; import java.io.*; import java.net.*; import java.util.*; import java.util.regex.*; import java.text.MessageFormat; import java.lang.annotation.*; import java.lang.reflect.*; import java.util.concurrent.*; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.lang.StringUtils; import org.apache.commons.beanutils.ConvertUtils; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.auth.AWSCredentials; import wwutil.sys.BaseXUtil; import wwutil.sys.ReflectUtil; import wwutil.model.AnnotationRegistry; import wwutil.model.AnnotationClassHandler; import wwutil.model.AnnotationFieldHandler; import wwutil.model.ValidationException; import wwutil.model.MaskMatcher; import wwutil.model.annotation.*; /** * Built-in data generation and validation functions. */ public class BuiltinFunc { private static Pattern sEmailPattern = Pattern.compile(EmailMatch.regex); private static AnnotationRegistry sPreStore1Registry = new AnnotationRegistry(); private static AnnotationRegistry sPreStore2Registry = new AnnotationRegistry(); private static AnnotationRegistry sValidationRegistry = new AnnotationRegistry(); private static AnnotationRegistry sPostLoadRegistry = new AnnotationRegistry(); static { try { setupBuiltinPreStore1Handlers(sPreStore1Registry); setupBuiltinPreStore2Handlers(sPreStore2Registry); setupBuiltinValidationHandlers(sValidationRegistry); setupBuiltinPostLoadHandlers(sPostLoadRegistry); } catch (Throwable e) { e.printStackTrace(); } } public static AnnotationRegistry clonePreStore1Registry() { return sPreStore1Registry.cloneRegistry(); } public static AnnotationRegistry clonePreStore2Registry() { return sPreStore2Registry.cloneRegistry(); } public static AnnotationRegistry cloneValidationRegistry() { return sValidationRegistry.cloneRegistry(); } public static AnnotationRegistry clonePostLoadRegistry() { return sPostLoadRegistry.cloneRegistry(); } //////////////////////////////////////////////////////////////////////////// // Stage 1 data handlers //////////////////////////////////////////////////////////////////////////// private static void setupBuiltinPreStore1Handlers(AnnotationRegistry registry) { registry.register(DefaultGUID.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != String.class) throw new ValidationException( "The @DefaultGUID field must be String type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { Object value = field.get(object); if (value == null || value.toString().length() == 0) { boolean isShort = ReflectUtil.getAnnoValue(fieldAnnotation, "isShort", false); String uuidStr = isShort ? BaseXUtil.uuid8() : BaseXUtil.uuid16(); field.set(object, uuidStr); } } }); registry.register(ModifiedTime.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != java.util.Date.class) throw new ValidationException( "The @ModifiedTime field must be java.util.Date type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { field.set(object, new Date()); } }); registry.register(VersionLocking.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != Integer.class && field.getType() != int.class) throw new ValidationException( "The @VersionLocking field must be int type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { ReflectUtil.incrementField(object, field, 1); } }); registry.register(ToUpper.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != String.class) throw new ValidationException( "The @ToUpper field must be String type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { String value = (String) field.get(object); if (value != null) { field.set(object, value.toUpperCase()); } } }); registry.register(ToLower.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != String.class) throw new ValidationException( "The @ToLower field must be String type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { String value = (String) field.get(object); if (value != null) { field.set(object, value.toLowerCase()); } } }); registry.register(Trim.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != String.class) throw new ValidationException( "The @Trim field must be String type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { String value = (String) field.get(object); if (value != null) { field.set(object, value.trim()); } } }); registry.register(RemoveChar.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != String.class) throw new ValidationException( "The @RemoveChar field must be String type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { char charToRemove = ReflectUtil.getAnnoValue(fieldAnnotation, "charToRemove", ' '); String value = (String) field.get(object); if (value != null) { field.set(object, StringUtils.remove(value, charToRemove)); } } }); registry.register(RemoveAlphaDigits.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != String.class) throw new ValidationException( "The @RemoveAlphaDigits field must be String type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { boolean removeDigits = ReflectUtil.getAnnoValue(fieldAnnotation, "removeDigits", false); String value = (String) field.get(object); if (value != null) { if (removeDigits) field.set(object, value.replaceAll("[\\d]", "")); // remove all digits else field.set(object, value.replaceAll("[^\\d]", "")); // remove all alphas (non-digits) } } }); registry.register(MaxValue.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != Integer.class && field.getType() != int.class && field.getType() != Long.class && field.getType() != long.class && field.getType() != Short.class && field.getType() != short.class && field.getType() != Float.class && field.getType() != float.class && field.getType() != Double.class && field.getType() != double.class) throw new ValidationException( "The @MaxValue field must be number type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { Object maxValueObj = ReflectUtil.getAnnoValue(fieldAnnotation, "value", (Object) null); double maxValue = ((Double) ConvertUtils.convert(maxValueObj, Double.class)).doubleValue(); Object valueObj = field.get(object); double value = ((Double) ConvertUtils.convert(valueObj, Double.class)).doubleValue(); value = (value > maxValue ? maxValue : value); field.set(object, ConvertUtils.convert(value, field.getType())); } }); registry.register(MinValue.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != Integer.class && field.getType() != int.class && field.getType() != Long.class && field.getType() != long.class && field.getType() != Short.class && field.getType() != short.class && field.getType() != Float.class && field.getType() != float.class && field.getType() != Double.class && field.getType() != double.class) throw new ValidationException( "The @MinValue field must be number type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { Object minValueObj = ReflectUtil.getAnnoValue(fieldAnnotation, "value", (Object) null); double minValue = ((Double) ConvertUtils.convert(minValueObj, Double.class)).doubleValue(); Object valueObj = field.get(object); double value = ((Double) ConvertUtils.convert(valueObj, Double.class)).doubleValue(); value = (value < minValue ? minValue : value); field.set(object, ConvertUtils.convert(value, field.getType())); } }); registry.register(AbsValue.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != Integer.class && field.getType() != int.class && field.getType() != Long.class && field.getType() != long.class && field.getType() != Short.class && field.getType() != short.class && field.getType() != Float.class && field.getType() != float.class && field.getType() != Double.class && field.getType() != double.class) throw new ValidationException( "The @AbsValue field must be number type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { Object valueObj = field.get(object); double value = ((Double) ConvertUtils.convert(valueObj, Double.class)).doubleValue(); value = Math.abs(value); field.set(object, ConvertUtils.convert(value, field.getType())); } }); registry.register(CeilValue.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != Integer.class && field.getType() != int.class && field.getType() != Long.class && field.getType() != long.class && field.getType() != Short.class && field.getType() != short.class && field.getType() != Float.class && field.getType() != float.class && field.getType() != Double.class && field.getType() != double.class) throw new ValidationException( "The @CeilValue field must be number type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { Object valueObj = field.get(object); double value = ((Double) ConvertUtils.convert(valueObj, Double.class)).doubleValue(); value = Math.ceil(value); field.set(object, ConvertUtils.convert(value, field.getType())); } }); registry.register(FloorValue.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != Integer.class && field.getType() != int.class && field.getType() != Long.class && field.getType() != long.class && field.getType() != Short.class && field.getType() != short.class && field.getType() != Float.class && field.getType() != float.class && field.getType() != Double.class && field.getType() != double.class) throw new ValidationException( "The @FloorValue field must be number type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { Object valueObj = field.get(object); double value = ((Double) ConvertUtils.convert(valueObj, Double.class)).doubleValue(); value = Math.floor(value); field.set(object, ConvertUtils.convert(value, field.getType())); } }); } //////////////////////////////////////////////////////////////////////////// // Stage 2 data handlers //////////////////////////////////////////////////////////////////////////// private static void setupBuiltinPreStore2Handlers(AnnotationRegistry registry) { registry.register(DefaultComposite.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != String.class) throw new ValidationException( "The @DefaultComposite field must be String type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { fillDefaultComposite(field, object, allFieldMap); } }); registry.register(FormatMsg.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != String.class) throw new ValidationException( "The @FormatMsg field must be String type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { FormatMsg formatMsg = (FormatMsg) fieldAnnotation; if (formatMsg.onSave()) { fillFormatMsg(formatMsg, field, object, allFieldMap); } } }); } //////////////////////////////////////////////////////////////////////////// // Validation handlers //////////////////////////////////////////////////////////////////////////// private static void setupBuiltinValidationHandlers(AnnotationRegistry registry) { registry.register(Required.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { if (field.get(object) == null) throw new ValidationException("@Required field cannot be null. Field: " + field.getName()); } }); registry.register(MaxSize.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != Integer.class && field.getType() != int.class && field.getType() != Long.class && field.getType() != long.class && field.getType() != Short.class && field.getType() != short.class && field.getType() != Float.class && field.getType() != float.class && field.getType() != Double.class && field.getType() != double.class && field.getType() != String.class) throw new ValidationException( "The @MaxSize field must be number type or String type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { Object annValueObj = ReflectUtil.getAnnoValue(fieldAnnotation, "value", (Object) null); double annValue = ((Double) ConvertUtils.convert(annValueObj, Double.class)).doubleValue(); if (annValue != 0) { Object valueObj = field.get(object); double value; if (valueObj instanceof String) value = ((String) valueObj).length(); else value = ((Double) ConvertUtils.convert(valueObj, Double.class)).doubleValue(); if (value > annValue) throw new ValidationException("Field value " + valueObj + " exceeds MaxSize " + annValueObj + ". Field: " + field.getName()); } } }); registry.register(MinSize.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != Integer.class && field.getType() != int.class && field.getType() != Long.class && field.getType() != long.class && field.getType() != Short.class && field.getType() != short.class && field.getType() != Float.class && field.getType() != float.class && field.getType() != Double.class && field.getType() != double.class && field.getType() != String.class) throw new ValidationException( "The @MinSize field must be number type or String type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { Object annValueObj = ReflectUtil.getAnnoValue(fieldAnnotation, "value", (Object) null); double annValue = ((Double) ConvertUtils.convert(annValueObj, Double.class)).doubleValue(); if (annValue != 0) { Object valueObj = field.get(object); double value; if (valueObj instanceof String) value = ((String) valueObj).length(); else value = ((Double) ConvertUtils.convert(valueObj, Double.class)).doubleValue(); if (value < annValue) throw new ValidationException("Field value " + valueObj + " is less than MinSize " + annValueObj + ". Field: " + field.getName()); } } }); registry.register(StartsWith.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != String.class) throw new ValidationException( "The @StartsWith field must be String type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { String annValue = ReflectUtil.getAnnoValue(fieldAnnotation, "value", ""); String value = (String) field.get(object); if (value != null && !value.startsWith(annValue)) throw new ValidationException("Field value " + value + " does not start with " + annValue + ". Field: " + field.getName()); } }); registry.register(EndsWith.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != String.class) throw new ValidationException( "The @EndsWith field must be String type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { String annValue = ReflectUtil.getAnnoValue(fieldAnnotation, "value", ""); String value = (String) field.get(object); if (value != null && !value.endsWith(annValue)) throw new ValidationException("Field value " + value + " does not end with " + annValue + ". Field: " + field.getName()); } }); registry.register(Contains.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != String.class) throw new ValidationException( "The @Contains field must be String type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { String annValue = ReflectUtil.getAnnoValue(fieldAnnotation, "value", ""); String value = (String) field.get(object); if (value != null && !value.contains(annValue)) throw new ValidationException("Field value " + value + " does not contain " + annValue + ". Field: " + field.getName()); } }); registry.register(NotContains.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != String.class) throw new ValidationException( "The @NotContains field must be String type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { String annValue = ReflectUtil.getAnnoValue(fieldAnnotation, "value", ""); String value = (String) field.get(object); if (value != null && value.contains(annValue)) throw new ValidationException( "Field value " + value + " contains " + annValue + ". Field: " + field.getName()); } }); registry.register(RegexMatch.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != String.class) throw new ValidationException( "The @RegexMatch field must be String type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { String annValue = ReflectUtil.getAnnoValue(fieldAnnotation, "value", ""); String value = (String) field.get(object); if (value != null && !Pattern.matches(annValue, value)) throw new ValidationException("Field value " + value + " does not match the regex " + annValue + ". Field: " + field.getName()); } }); registry.register(EmailMatch.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != String.class) throw new ValidationException( "The @EmailMatch field must be String type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { String value = (String) field.get(object); if (value != null) { if (!sEmailPattern.matcher(value.toUpperCase()).matches()) throw new ValidationException( "Field value " + value + " is not an email. Field: " + field.getName()); } } }); registry.register(MaskMatch.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != String.class) throw new ValidationException( "The @MaskMatch field must be String type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { char digitMask = ReflectUtil.getAnnoValue(fieldAnnotation, "digitMask", '#'); char letterMask = ReflectUtil.getAnnoValue(fieldAnnotation, "letterMask", '@'); char anyMask = ReflectUtil.getAnnoValue(fieldAnnotation, "anyMask", '*'); String pattern = ReflectUtil.getAnnoValue(fieldAnnotation, "pattern", ""); String value = (String) field.get(object); if (value != null) { MaskMatcher matcher = new MaskMatcher(pattern, digitMask, letterMask, anyMask); if (!matcher.matches(value)) throw new ValidationException("Field value " + value + " does not match the mask pattern " + pattern + ". Field: " + field.getName()); } } }); registry.register(OneOf.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != String.class) throw new ValidationException( "The @OneOf field must be String type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { String[] annValue = (String[]) ReflectUtil.getAnnoValue(fieldAnnotation, "choices", new String[0]); String value = (String) field.get(object); if (value != null) { for (String choice : annValue) { if (value.equals(choice)) return; } throw new ValidationException( "Field value " + value + " is not one of the choices. Field: " + field.getName()); } } }); } //////////////////////////////////////////////////////////////////////////// // Stage 2 data handlers //////////////////////////////////////////////////////////////////////////// private static void setupBuiltinPostLoadHandlers(AnnotationRegistry registry) { registry.register(FormatMsg.class, new AnnotationFieldHandler() { public void checkModel(Annotation fieldAnnotation, Field field, Map<String, Field> allFieldMap) throws ValidationException { if (field.getType() != String.class) throw new ValidationException( "The @FormatMsg field must be String type. Field: " + field.getName()); } public void handle(Annotation fieldAnnotation, Object object, Field field, Map<String, Field> allFieldMap) throws Exception { FormatMsg formatMsg = (FormatMsg) fieldAnnotation; if (formatMsg.onLoad()) { fillFormatMsg(formatMsg, field, object, allFieldMap); } } }); } private static void fillDefaultComposite(Field field, Object dataObj, Map<String, Field> allFieldMap) throws Exception { String[] fromFields = ReflectUtil.getAnnotationValue(field, DefaultComposite.class, "fromFields", String[].class, new String[0]); int[] substrLen = ReflectUtil.getAnnotationValue(field, DefaultComposite.class, "substrLen", int[].class, new int[0]); String separator = ReflectUtil.getAnnotationValue(field, DefaultComposite.class, "separator", "-"); StringBuilder sb = new StringBuilder(); for (int i = 0; i < fromFields.length; i++) { Field subpartField = allFieldMap.get(fromFields[i]); if (subpartField == null) throw new IllegalArgumentException( fromFields[i] + " specified in the fromFields parameter of the @DefaultComposite field " + field.getName() + " doesn't exist."); Object subpartValue = subpartField.get(dataObj); String subpartStr = subpartValue == null ? "" : subpartValue.toString(); subpartStr = getSubpartMax(subpartStr, i, substrLen); if (subpartStr.length() > 0) { if (sb.length() > 0) sb.append(separator); sb.append(subpartStr); } } field.set(dataObj, sb.toString()); } private static String getSubpartMax(String fieldStr, int fieldPos, int[] substrLen) { if (substrLen == null || fieldPos >= substrLen.length || substrLen[fieldPos] == 0) return fieldStr; int len = substrLen[fieldPos] > fieldStr.length() ? fieldStr.length() : substrLen[fieldPos]; return fieldStr.substring(0, len); } private static void fillFormatMsg(FormatMsg formatMsg, Field field, Object dataObj, Map<String, Field> allFieldMap) throws Exception { Object[] paramObjs = new Object[formatMsg.paramFields().length]; for (int i = 0; i < formatMsg.paramFields().length; i++) { Field paramField = allFieldMap.get(formatMsg.paramFields()[i]); if (paramField == null) throw new IllegalArgumentException(formatMsg.paramFields()[i] + " specified in the paramFields parameter of the @FormatMsg field " + field.getName() + " doesn't exist."); paramObjs[i] = paramField.get(dataObj); } String msg = MessageFormat.format(formatMsg.format(), paramObjs); field.set(dataObj, msg); } }