// Path: src/main/java/com/tngtech/configbuilder/configuration/BuilderConfiguration.java
// public class BuilderConfiguration {
// 
//     private Properties properties;
//     private CommandLine commandLine;
//     private Object importedConfiguration;
//     private Class<? extends Annotation>[] annotationOrder = new Class[]{CommandLineValue.class, PropertyValue.class, EnvironmentVariableValue.class, SystemPropertyValue.class, ImportedValue.class, DefaultValue.class};
// 
//     public BuilderConfiguration() {
//         properties = new Properties();
//         commandLine = null;
//         importedConfiguration = null;
//     }
// 
//     public CommandLine getCommandLine() {
//         return commandLine;
//     }
// 
//     public Properties getProperties() {
//         return properties;
//     }
// 
//     public Object getImportedConfiguration() {
//         return importedConfiguration;
//     }
// 
//     public void setProperties(Properties properties) {
//         this.properties = properties;
//     }
// 
//     public void setCommandLine(CommandLine commandLine) {
//         this.commandLine = commandLine;
//     }
// 
//     public void setImportedConfiguration(Object importedConfiguration) {
//         this.importedConfiguration = importedConfiguration;
//     }
// 
//     public void setAnnotationOrder(Class<? extends Annotation>[] annotationOrder) {
//         this.annotationOrder = annotationOrder;
//     }
// 
//     public Class<? extends Annotation>[] getAnnotationOrder() {
//         return annotationOrder;
//     }
// }
// 
// Path: src/main/java/com/tngtech/configbuilder/configuration/ErrorMessageSetup.java
// public class ErrorMessageSetup {
// 
//     private Properties errorMessages;
// 
//     /**
//      * loads the default error messages for the system locale, then merges them with additional error messages loaded with the PropertyLoader
//      *
//      * @param baseName       the filename for additional error messages
//      * @param propertyLoader the PropertyLoader used to load additional error messages
//      */
//     public void initialize(String baseName, PropertyLoader propertyLoader) {
//         ResourceBundle resourceBundle = ResourceBundle.getBundle("errors");
//         errorMessages = convertResourceBundleToProperties(resourceBundle);
//         if (baseName != null) {
//             errorMessages.putAll(propertyLoader.load(baseName));
//         }
//     }
// 
//     private Properties convertResourceBundleToProperties(ResourceBundle resource) {
//         Properties properties = new Properties();
// 
//         Enumeration<String> keys = resource.getKeys();
//         while (keys.hasMoreElements()) {
//             String key = keys.nextElement();
//             properties.put(key, resource.getString(key));
//         }
//         return properties;
//     }
// 
//     public String getErrorMessage(Throwable e, String... variables) {
//         String message = errorMessages.getProperty(e.getClass().getName());
//         return message == null ? String.format(errorMessages.getProperty("standardMessage"), e.getClass().getName()) : String.format(message, variables);
//     }
// 
//     public String getErrorMessage(Class exceptionClass, String... variables) {
//         String message = errorMessages.getProperty(exceptionClass.getName());
//         return message == null ? String.format(errorMessages.getProperty("standardMessage"), exceptionClass.getName()) : String.format(message, variables);
//     }
// }
// 
// Path: src/main/java/com/tngtech/configbuilder/exception/ConfigBuilderException.java
// public class ConfigBuilderException extends RuntimeException {
// 
//     public ConfigBuilderException(String message, Throwable e) {
//         super(message, e);
//     }
// }


import com.tngtech.configbuilder.annotation.valueextractor.ValueExtractorAnnotation;
import com.tngtech.configbuilder.configuration.BuilderConfiguration;
import com.tngtech.configbuilder.configuration.ErrorMessageSetup;
import com.tngtech.configbuilder.exception.ConfigBuilderException;
import org.apache.log4j.Logger;
import java.lang.reflect.Field;
package com.tngtech.configbuilder.util;



public class FieldSetter<T> {

    private final static Logger log = Logger.getLogger(FieldSetter.class);

    private final FieldValueTransformer fieldValueTransformer;
    private final FieldValueExtractor fieldValueExtractor;
    private final ErrorMessageSetup errorMessageSetup;
    private final AnnotationHelper annotationHelper;

    public FieldSetter(ConfigBuilderFactory configBuilderFactory) {
        this.annotationHelper = configBuilderFactory.getInstance(AnnotationHelper.class);
        this.errorMessageSetup = configBuilderFactory.getInstance(ErrorMessageSetup.class);
        this.fieldValueTransformer = configBuilderFactory.getInstance(FieldValueTransformer.class);
        this.fieldValueExtractor = configBuilderFactory.getInstance(FieldValueExtractor.class);
    }

    public void setFields(T instanceOfConfigClass, BuilderConfiguration builderConfiguration) {

        for (Field field : instanceOfConfigClass.getClass().getDeclaredFields()) {
            if (annotationHelper.fieldHasAnnotationAnnotatedWith(field, ValueExtractorAnnotation.class)) {
                Object value = fieldValueExtractor.extractValue(field, builderConfiguration);
                value = fieldValueTransformer.transformFieldValue(field, value);
                setField(instanceOfConfigClass, field, value);
            } else {
                log.debug(String.format("field %s is not annotated with any ValueExtractorAnnotation: skipping field", field.getName()));
            }
        }
    }

    private void setField(T instanceOfConfigClass, Field field, Object value) {
        try {
            field.setAccessible(true);
            if(value == null && field.getType().isPrimitive()) {
                log.warn(String.format("no value found for field %s of primitive type %s: field will be initialized to default", field.getName(), field.getType().getName()));
            }
// Path: src/main/java/com/tngtech/configbuilder/configuration/BuilderConfiguration.java
// public class BuilderConfiguration {
// 
//     private Properties properties;
//     private CommandLine commandLine;
//     private Object importedConfiguration;
//     private Class<? extends Annotation>[] annotationOrder = new Class[]{CommandLineValue.class, PropertyValue.class, EnvironmentVariableValue.class, SystemPropertyValue.class, ImportedValue.class, DefaultValue.class};
// 
//     public BuilderConfiguration() {
//         properties = new Properties();
//         commandLine = null;
//         importedConfiguration = null;
//     }
// 
//     public CommandLine getCommandLine() {
//         return commandLine;
//     }
// 
//     public Properties getProperties() {
//         return properties;
//     }
// 
//     public Object getImportedConfiguration() {
//         return importedConfiguration;
//     }
// 
//     public void setProperties(Properties properties) {
//         this.properties = properties;
//     }
// 
//     public void setCommandLine(CommandLine commandLine) {
//         this.commandLine = commandLine;
//     }
// 
//     public void setImportedConfiguration(Object importedConfiguration) {
//         this.importedConfiguration = importedConfiguration;
//     }
// 
//     public void setAnnotationOrder(Class<? extends Annotation>[] annotationOrder) {
//         this.annotationOrder = annotationOrder;
//     }
// 
//     public Class<? extends Annotation>[] getAnnotationOrder() {
//         return annotationOrder;
//     }
// }
// 
// Path: src/main/java/com/tngtech/configbuilder/configuration/ErrorMessageSetup.java
// public class ErrorMessageSetup {
// 
//     private Properties errorMessages;
// 
//     /**
//      * loads the default error messages for the system locale, then merges them with additional error messages loaded with the PropertyLoader
//      *
//      * @param baseName       the filename for additional error messages
//      * @param propertyLoader the PropertyLoader used to load additional error messages
//      */
//     public void initialize(String baseName, PropertyLoader propertyLoader) {
//         ResourceBundle resourceBundle = ResourceBundle.getBundle("errors");
//         errorMessages = convertResourceBundleToProperties(resourceBundle);
//         if (baseName != null) {
//             errorMessages.putAll(propertyLoader.load(baseName));
//         }
//     }
// 
//     private Properties convertResourceBundleToProperties(ResourceBundle resource) {
//         Properties properties = new Properties();
// 
//         Enumeration<String> keys = resource.getKeys();
//         while (keys.hasMoreElements()) {
//             String key = keys.nextElement();
//             properties.put(key, resource.getString(key));
//         }
//         return properties;
//     }
// 
//     public String getErrorMessage(Throwable e, String... variables) {
//         String message = errorMessages.getProperty(e.getClass().getName());
//         return message == null ? String.format(errorMessages.getProperty("standardMessage"), e.getClass().getName()) : String.format(message, variables);
//     }
// 
//     public String getErrorMessage(Class exceptionClass, String... variables) {
//         String message = errorMessages.getProperty(exceptionClass.getName());
//         return message == null ? String.format(errorMessages.getProperty("standardMessage"), exceptionClass.getName()) : String.format(message, variables);
//     }
// }
// 
// Path: src/main/java/com/tngtech/configbuilder/exception/ConfigBuilderException.java
// public class ConfigBuilderException extends RuntimeException {
// 
//     public ConfigBuilderException(String message, Throwable e) {
//         super(message, e);
//     }
// }


// Path: src/main/java/com/tngtech/configbuilder/util/FieldSetter.java
import com.tngtech.configbuilder.annotation.valueextractor.ValueExtractorAnnotation;
import com.tngtech.configbuilder.configuration.BuilderConfiguration;
import com.tngtech.configbuilder.configuration.ErrorMessageSetup;
import com.tngtech.configbuilder.exception.ConfigBuilderException;
import org.apache.log4j.Logger;
import java.lang.reflect.Field;

package com.tngtech.configbuilder.util;



public class FieldSetter<T> {

    private final static Logger log = Logger.getLogger(FieldSetter.class);

    private final FieldValueTransformer fieldValueTransformer;
    private final FieldValueExtractor fieldValueExtractor;
    private final ErrorMessageSetup errorMessageSetup;
    private final AnnotationHelper annotationHelper;

    public FieldSetter(ConfigBuilderFactory configBuilderFactory) {
        this.annotationHelper = configBuilderFactory.getInstance(AnnotationHelper.class);
        this.errorMessageSetup = configBuilderFactory.getInstance(ErrorMessageSetup.class);
        this.fieldValueTransformer = configBuilderFactory.getInstance(FieldValueTransformer.class);
        this.fieldValueExtractor = configBuilderFactory.getInstance(FieldValueExtractor.class);
    }

    public void setFields(T instanceOfConfigClass, BuilderConfiguration builderConfiguration) {

        for (Field field : instanceOfConfigClass.getClass().getDeclaredFields()) {
            if (annotationHelper.fieldHasAnnotationAnnotatedWith(field, ValueExtractorAnnotation.class)) {
                Object value = fieldValueExtractor.extractValue(field, builderConfiguration);
                value = fieldValueTransformer.transformFieldValue(field, value);
                setField(instanceOfConfigClass, field, value);
            } else {
                log.debug(String.format("field %s is not annotated with any ValueExtractorAnnotation: skipping field", field.getName()));
            }
        }
    }

    private void setField(T instanceOfConfigClass, Field field, Object value) {
        try {
            field.setAccessible(true);
            if(value == null && field.getType().isPrimitive()) {
                log.warn(String.format("no value found for field %s of primitive type %s: field will be initialized to default", field.getName(), field.getType().getName()));
            }
            else {