Map<String, HandlerConfigProperty> getConfigPropertiesByName(Class configClass) throws ConfigBuilderException { List<HandlerConfigProperty> properties = getConfigProperties(configClass); return properties.stream().collect(toMap(HandlerConfigProperty::getName, identity())); }
public <C> C buildConfig(Class<C> configClass, Properties properties) throws ConfigBuilderException { Map<String, HandlerConfigProperty> configPropertiesByName = configPropertyParser.getConfigPropertiesByName(configClass); C configInstance; try { configInstance = configClass.newInstance(); } catch (Exception e) { throw new ConfigBuilderException("Failed to instantiate config class " + configClass.getSimpleName() + " - " + e.getClass().getSimpleName(), e); } //iterate sorted by field name for consistent/deterministic behaviour List<String> props = configPropertiesByName.keySet().stream().sorted().collect(Collectors.toList()); for ( String configPropertyName : props) { log.debug("Processing config property " + configPropertyName); HandlerConfigPropertyImpl configProperty = (HandlerConfigPropertyImpl)configPropertiesByName.get(configPropertyName); String propertyValue = properties.getProperty(configPropertyName); setValueForConfigProperty(configInstance, configPropertyName, configProperty, propertyValue); } warnOnUnusedProperties(properties, configPropertiesByName); runClassLevelValidation(configClass, configInstance); return configInstance; }
List<HandlerConfigProperty> getConfigProperties(Class configClass) throws ConfigBuilderException { Method[] methods = getMethodsFromConfigClass(configClass); List<HandlerConfigProperty> result = new LinkedList<>(); List<Method> l = Arrays.stream(methods) .filter(m -> m.isAnnotationPresent(ConfigProperty.class)) .collect(Collectors.toList()); for (Method m : l) { addConfigProperty(result, m); } return result; }
List<Method> getValidationMethods(Class configClass) throws ConfigBuilderException { Method[] methods = getMethodsFromConfigClass(configClass); List<Method> result = new LinkedList<>(); for (Method m : methods) { if (m.isAnnotationPresent(ConfigValidator.class) && checkValidationMethod(m, configClass)) { result.add(m); } } return result; }
private Optional<Pattern> getValidationPattern(ConfigProperty p, Class javaType) throws ConfigBuilderException { Optional<Pattern> pattern = p.validationPattern().equals("") ? getDefaultValidationPattern(javaType) : Optional.of(compilePattern(p)); return pattern; }
throw new ConfigBuilderException( "A config bean can only annotate a setter method (the method " + method.getName() + " does not start with 'set'), for " + getAnnotationDescription(p)); "The annotated method must take a single argument, for " + getAnnotationDescription(p) ); Optional<Pattern> validationPattern = getValidationPattern(p, javaType); ConfigBuilderTypeConverter converterFunction = getConverterFunction(p, javaType); validateDefaultValue(validationPattern.get(), p); defaultValue = convertDefaultValue(p, converterFunction, javaType); if (javaType != defaultValue.getClass()) { throw new ConfigBuilderException("Default value \"" + p.defaultValue() + "\" was converted to a type " + defaultValue.getClass().getName() + " which did not match the expected class type " + javaType.getName() + " for " + getAnnotationDescription(p));
private void validateDefaultValue(Pattern validationPattern, ConfigProperty p) throws ConfigBuilderException { if (!validationPattern.matcher(p.defaultValue()).matches()) { throw new ConfigBuilderException( String.format("The default value [%s] did not match the validation pattern [%s], for %s", p.defaultValue(), validationPattern.pattern(), getAnnotationDescription(p) ) ); } }
private ConfigBuilderTypeConverter getConverterFunction(ConfigProperty p, Class javaType) throws ConfigBuilderException { ConfigBuilderTypeConverter f; try { Class<? extends ConfigBuilderTypeConverter> c = p.valueConverter(); f = c.newInstance(); } catch (Exception e) { throw new ConfigBuilderException("Failed to instantiate converter class " + p.valueConverter().getClass().getName() + " for " + getAnnotationDescription(p), e); } return f; }
@Test(expected = ConfigBuilderException.class) public void anAnnotationOnAMethodWithNoArgumentThrowsAnException() throws ConfigBuilderException { configPropertyParser.getConfigProperties(ConfigBeanWithAnnotationOnSetterWithNoArgument.class); }
@Test public void primitiveTypedPropertiesGetDefaultValidation() throws ConfigBuilderException { Map<String, HandlerConfigProperty> m = configPropertyParser.getConfigPropertiesByName(ConfigBeanWithPrimitiveTypedProperties.class); assertEquals("^[-+]?\\d+$", m.get("integerProperty").getValidationPattern().get().pattern()); assertEquals("^[-+]?\\d+$", m.get("longProperty").getValidationPattern().get().pattern()); assertEquals("^[-+]?\\d+$", m.get("shortProperty").getValidationPattern().get().pattern()); assertEquals("^[-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?$", m.get("floatProperty").getValidationPattern().get().pattern()); assertEquals("^[-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?$", m.get("doubleProperty").getValidationPattern().get().pattern()); assertEquals("(?i)^true|false$", m.get("booleanProperty").getValidationPattern().get().pattern()); assertEquals("^\\S$", m.get("charProperty").getValidationPattern().get().pattern()); }
private Pattern compilePattern(ConfigProperty p) throws ConfigBuilderException { Pattern pattern; try { pattern = Pattern.compile(p.validationPattern()); } catch (PatternSyntaxException e) { throw new ConfigBuilderException("The validation pattern '" + p.validationPattern() + "' could not be compiled, for " + getAnnotationDescription(p)); } return pattern; }
@Test(expected = ConfigBuilderException.class) public void anAnnotationOnAMethodWhichDoesNotStartWithSetThrowsAnException() throws ConfigBuilderException { configPropertyParser.getConfigProperties(ConfigBeanWithAnnotationOnMethodWhichDoesNotStartWithSet.class); }
@Test public void defaultValuesCanBeConvertedToSimpleTypes() throws ConfigBuilderException { Map<String, HandlerConfigProperty> m = configPropertyParser.getConfigPropertiesByName(ConfigBeanWithPrimitiveTypedProperties.class); assertEquals(7, m.size()); assertEquals(1, m.get("integerProperty").getDefaultValue().get()); assertEquals(1000000L, m.get("longProperty").getDefaultValue().get()); assertEquals(1.23d, m.get("doubleProperty").getDefaultValue().get()); assertEquals(2.34f, m.get("floatProperty").getDefaultValue().get()); assertEquals(true, m.get("booleanProperty").getDefaultValue().get()); assertEquals('C', m.get("charProperty").getDefaultValue().get()); assertEquals((short)9, m.get("shortProperty").getDefaultValue().get()); }
@Test public void aBeanWithNoAnnotatedMethodsProducesAnEmptyList() throws ConfigBuilderException { List properties = configPropertyParser.getConfigProperties(ConfigBeanWithNoAnnotatedProperties.class); assertEquals(0, properties.size()); }
@Test public void testDefaultValuesWhichDoNotMatchValidationPatternThrowException() { try { configPropertyParser.getConfigProperties(ConfigBeanWithADefaultValueWhichDoesNotSatisfyValidation.class); fail("Should fail to convert"); } catch (Exception e) { System.out.println(e.getMessage()); assertEquals("The default value [the other] did not match the validation pattern [(this|that)], for ConfigProperty annotation with name prop", e.getMessage()); } }
@Test public void testAValidationPatternWhichCannotCompileThrowsException() { try { configPropertyParser.getConfigProperties(ConfigBeanWithAValidationPatternWhichCannotBeCompiled.class); fail("Should fail to convert"); } catch (Exception e) { System.out.println(e.getMessage()); assertEquals("The validation pattern '^&*(%' could not be compiled, for ConfigProperty annotation with name prop", e.getMessage()); } }
@Test public void testAValidationPatternCanBeSetWithoutADefaultValue() throws ConfigBuilderException { List<HandlerConfigProperty> properties = configPropertyParser.getConfigProperties(ConfigBeanWithValidationPatternAndNoDefaultValue.class); HandlerConfigProperty p = properties.get(0); assertEquals("test.*", p.getValidationPattern().get().pattern()); }
@Test public void testDefaultValuesWhichCannotBeConvertedToJavaTypeThrowsException() { try { configPropertyParser.getConfigProperties(ConfigBeanWithADefaultValueWhichCannotConvertToJavaType.class); fail("Should fail to convert"); } catch (Exception e) { System.out.println(e.getMessage()); assertEquals("The default value [wibble] did not match the validation pattern [^[-+]?\\d+$], for ConfigProperty annotation with name badDefaultProperty", e.getMessage()); } }
@Test public void aPropertyCanBeConfiguredNotMandatory() throws ConfigBuilderException { List<HandlerConfigProperty> properties = configPropertyParser.getConfigProperties(ConfigBeanPropertyCanBeConfiguredNotMandatory.class); assertEquals(1, properties.size()); HandlerConfigProperty p = properties.get(0); assertFalse( p.isMandatory()); }
@Test public void enumFieldsCanBeParsed() throws ConfigBuilderException { List<HandlerConfigProperty> properties = configPropertyParser.getConfigProperties(ConfigBeanWithEnumTypes.class); assertEquals(1, properties.size()); HandlerConfigProperty p = properties.get(0); assertEquals( p.getJavaType(), Scope.class); }