// Path: copybook4java/src/main/java/com/nordea/oss/copybook/converters/TypeConverter.java
// public interface TypeConverter {
//     void initialize(TypeConverterConfig config);
//     void validate(Class<?> type, int size, int decimals);
//     TypeConverter copy(Class<?> type) throws IllegalAccessException, InstantiationException;
//     Object to(byte[] bytes, int offset, int length, int decimals, boolean removePadding);
//     byte[] from(Object value, int length, int decimals, boolean addPadding);
// }
// 
// Path: copybook4java/src/main/java/com/nordea/oss/copybook/converters/TypeConverterConfig.java
// public class TypeConverterConfig {
//     private Charset charset;
//     private CopyBookFieldSigningType signingType;
//     private boolean rightPadding;
//     private char paddingChar;
//     private char nullFillerChar;
//     private String defaultValue;
//     private String format;
// 
//     public TypeConverterConfig() {
//     }
// 
//     public Charset getCharset() {
//         return charset;
//     }
// 
//     public void setCharset(Charset charset) {
//         this.charset = charset;
//     }
// 
//     public CopyBookFieldSigningType getSigningType() {
//         return signingType;
//     }
// 
//     public void setSigningType(CopyBookFieldSigningType signingType) {
//         this.signingType = signingType;
//     }
// 
//     public boolean isRightPadding() {
//         return rightPadding;
//     }
// 
//     public void setRightPadding(boolean rightPadding) {
//         this.rightPadding = rightPadding;
//     }
// 
//     public char getPaddingChar() {
//         return paddingChar;
//     }
// 
//     public void setPaddingChar(char paddingChar) {
//         this.paddingChar = paddingChar;
//     }
// 
//     public char getNullFillerChar() {
//         return nullFillerChar;
//     }
// 
//     public void setNullFillerChar(char nullFillerChar) {
//         this.nullFillerChar = nullFillerChar;
//     }
// 
//     public String getDefaultValue() {
//         return defaultValue;
//     }
// 
//     public void setDefaultValue(String defaultValue) {
//         this.defaultValue = defaultValue;
//     }
// 
//     public String getFormat() {
//         return format;
//     }
// 
//     public void setFormat(String format) {
//         this.format = format;
//     }
// }
// 
// Path: copybook4java/src/main/java/com/nordea/oss/copybook/exceptions/CopyBookException.java
// public class CopyBookException extends RuntimeException {
//     private static final long serialVersionUID = 28118369047109260L;
//     public CopyBookException(String message) {
//         super(message);
//     }
// 
//     public CopyBookException(String message, TypeConverterException ex) {
//         super(message + ": " + ex.getClass().getSimpleName() + " :" + ex.getMessage());
//     }
// 
//     public CopyBookException(String message, Exception ex) {
//         super(message + ": " + ex.getClass().getSimpleName() + " :" + ex.getMessage());
//     }
// }
// 
// Path: copybook4java/src/main/java/com/nordea/oss/copybook/exceptions/TypeConverterException.java
// public class TypeConverterException extends RuntimeException {
//     private static final long serialVersionUID = -7577535992947276304L;
//     public TypeConverterException(String message) {
//         super(message);
//     }
// }


import com.nordea.oss.copybook.annotations.*;
import com.nordea.oss.copybook.converters.TypeConverter;
import com.nordea.oss.copybook.converters.TypeConverterConfig;
import com.nordea.oss.copybook.exceptions.CopyBookException;
import com.nordea.oss.copybook.exceptions.TypeConverterException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
            case "byte": return "Byte";
            case "void": return "Void";
            default: return type.getSimpleName();
        }
    }

    @SuppressWarnings("unchecked")
    private <T extends Annotation> List<T> getAnnotationsRecursively(Class<?> type, Class<T> annotationType) {
        List<T> results = new ArrayList<>();
        for (Annotation annotation : type.getAnnotations()) {
            if(annotationType.isInstance(annotation)) {
                results.add((T)annotation);

            } else if (annotation.annotationType().getAnnotation(annotationType) != null) {
                results.addAll(getAnnotationsRecursively(annotation.annotationType(), annotationType));
            }
        }
        return results;
    }

    private Map<String, TypeConverter> getTypeConvertersRecursively(Class<?> type, Charset charset, Boolean strict) {
        Map<String,TypeConverter> results = new HashMap<>();
        for (Annotation annotation : type.getAnnotations()) {
            if(CopyBookFieldFormats.class.isInstance(annotation)) {
                for(CopyBookFieldFormat fieldFormat : ((CopyBookFieldFormats)annotation).value()) {
                    results.put(fieldFormat.type().getSimpleName(), createTypeConverter(fieldFormat, charset, strict));
                }

            } else if(CopyBookFieldFormat.class.isInstance(annotation)) {
                CopyBookFieldFormat fieldFormat = (CopyBookFieldFormat)annotation;
// Path: copybook4java/src/main/java/com/nordea/oss/copybook/converters/TypeConverter.java
// public interface TypeConverter {
//     void initialize(TypeConverterConfig config);
//     void validate(Class<?> type, int size, int decimals);
//     TypeConverter copy(Class<?> type) throws IllegalAccessException, InstantiationException;
//     Object to(byte[] bytes, int offset, int length, int decimals, boolean removePadding);
//     byte[] from(Object value, int length, int decimals, boolean addPadding);
// }
// 
// Path: copybook4java/src/main/java/com/nordea/oss/copybook/converters/TypeConverterConfig.java
// public class TypeConverterConfig {
//     private Charset charset;
//     private CopyBookFieldSigningType signingType;
//     private boolean rightPadding;
//     private char paddingChar;
//     private char nullFillerChar;
//     private String defaultValue;
//     private String format;
// 
//     public TypeConverterConfig() {
//     }
// 
//     public Charset getCharset() {
//         return charset;
//     }
// 
//     public void setCharset(Charset charset) {
//         this.charset = charset;
//     }
// 
//     public CopyBookFieldSigningType getSigningType() {
//         return signingType;
//     }
// 
//     public void setSigningType(CopyBookFieldSigningType signingType) {
//         this.signingType = signingType;
//     }
// 
//     public boolean isRightPadding() {
//         return rightPadding;
//     }
// 
//     public void setRightPadding(boolean rightPadding) {
//         this.rightPadding = rightPadding;
//     }
// 
//     public char getPaddingChar() {
//         return paddingChar;
//     }
// 
//     public void setPaddingChar(char paddingChar) {
//         this.paddingChar = paddingChar;
//     }
// 
//     public char getNullFillerChar() {
//         return nullFillerChar;
//     }
// 
//     public void setNullFillerChar(char nullFillerChar) {
//         this.nullFillerChar = nullFillerChar;
//     }
// 
//     public String getDefaultValue() {
//         return defaultValue;
//     }
// 
//     public void setDefaultValue(String defaultValue) {
//         this.defaultValue = defaultValue;
//     }
// 
//     public String getFormat() {
//         return format;
//     }
// 
//     public void setFormat(String format) {
//         this.format = format;
//     }
// }
// 
// Path: copybook4java/src/main/java/com/nordea/oss/copybook/exceptions/CopyBookException.java
// public class CopyBookException extends RuntimeException {
//     private static final long serialVersionUID = 28118369047109260L;
//     public CopyBookException(String message) {
//         super(message);
//     }
// 
//     public CopyBookException(String message, TypeConverterException ex) {
//         super(message + ": " + ex.getClass().getSimpleName() + " :" + ex.getMessage());
//     }
// 
//     public CopyBookException(String message, Exception ex) {
//         super(message + ": " + ex.getClass().getSimpleName() + " :" + ex.getMessage());
//     }
// }
// 
// Path: copybook4java/src/main/java/com/nordea/oss/copybook/exceptions/TypeConverterException.java
// public class TypeConverterException extends RuntimeException {
//     private static final long serialVersionUID = -7577535992947276304L;
//     public TypeConverterException(String message) {
//         super(message);
//     }
// }


// Path: copybook4java/src/main/java/com/nordea/oss/copybook/serializers/CopyBookParser.java
import com.nordea.oss.copybook.annotations.*;
import com.nordea.oss.copybook.converters.TypeConverter;
import com.nordea.oss.copybook.converters.TypeConverterConfig;
import com.nordea.oss.copybook.exceptions.CopyBookException;
import com.nordea.oss.copybook.exceptions.TypeConverterException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

            case "byte": return "Byte";
            case "void": return "Void";
            default: return type.getSimpleName();
        }
    }

    @SuppressWarnings("unchecked")
    private <T extends Annotation> List<T> getAnnotationsRecursively(Class<?> type, Class<T> annotationType) {
        List<T> results = new ArrayList<>();
        for (Annotation annotation : type.getAnnotations()) {
            if(annotationType.isInstance(annotation)) {
                results.add((T)annotation);

            } else if (annotation.annotationType().getAnnotation(annotationType) != null) {
                results.addAll(getAnnotationsRecursively(annotation.annotationType(), annotationType));
            }
        }
        return results;
    }

    private Map<String, TypeConverter> getTypeConvertersRecursively(Class<?> type, Charset charset, Boolean strict) {
        Map<String,TypeConverter> results = new HashMap<>();
        for (Annotation annotation : type.getAnnotations()) {
            if(CopyBookFieldFormats.class.isInstance(annotation)) {
                for(CopyBookFieldFormat fieldFormat : ((CopyBookFieldFormats)annotation).value()) {
                    results.put(fieldFormat.type().getSimpleName(), createTypeConverter(fieldFormat, charset, strict));
                }

            } else if(CopyBookFieldFormat.class.isInstance(annotation)) {
                CopyBookFieldFormat fieldFormat = (CopyBookFieldFormat)annotation;
                results.put(fieldFormat.type().getSimpleName(), createTypeConverter(fieldFormat, charset, strict));