001package org.kuali.common.util.bind.test;
002
003import static com.google.common.base.Preconditions.checkNotNull;
004
005import java.lang.annotation.Annotation;
006import java.lang.reflect.Field;
007import java.util.Collections;
008import java.util.Comparator;
009import java.util.List;
010
011import org.kuali.common.util.ReflectionUtils;
012import org.kuali.common.util.tree.ImmutableNode;
013import org.kuali.common.util.tree.MutableNode;
014import org.kuali.common.util.tree.Node;
015
016import com.google.common.collect.ImmutableList;
017import com.google.common.collect.Lists;
018
019public final class AnnotatedFieldAssembler implements Assembler<List<Node<Field>>> {
020
021        private final Class<? extends Annotation> annotation;
022        private final Class<?> type;
023        private final Comparator<Field> comparator;
024
025        @Override
026        public List<Node<Field>> assemble() {
027                List<MutableNode<Field>> assembled = assemble(type);
028                List<Node<Field>> list = Lists.newArrayList();
029                for (Node<Field> element : assembled) {
030                        list.add(ImmutableNode.copyOf(element));
031                }
032                return ImmutableList.copyOf(list);
033        }
034
035        protected List<MutableNode<Field>> assemble(Class<?> type) {
036                List<Field> fields = getSortedFields(type);
037                List<MutableNode<Field>> list = Lists.newArrayList();
038                for (Field field : fields) {
039                        list.add(getNode(field));
040                }
041                return list;
042        }
043
044        protected MutableNode<Field> getNode(Field field) {
045                MutableNode<Field> node = new MutableNode<Field>(field);
046                if (field.isAnnotationPresent(annotation)) {
047                        node.add(assemble(field.getType()));
048                }
049                return node;
050        }
051
052        protected List<Field> getSortedFields(Class<?> type) {
053                List<Field> fields = Lists.newArrayList(ReflectionUtils.getAllFields(type));
054                Collections.sort(fields, comparator);
055                return fields;
056        }
057
058        private AnnotatedFieldAssembler(Builder builder) {
059                this.annotation = builder.annotation;
060                this.type = builder.type;
061                this.comparator = builder.comparator;
062        }
063
064        public static AnnotatedFieldAssembler create(Class<?> type, Class<? extends Annotation> annotation) {
065                return builder(type, annotation).build();
066        }
067
068        public static Builder builder(Class<?> type, Class<? extends Annotation> annotation) {
069                return new Builder(type, annotation);
070        }
071
072        public static class Builder implements org.apache.commons.lang3.builder.Builder<AnnotatedFieldAssembler> {
073
074                // Required
075                private final Class<?> type;
076                private final Class<? extends Annotation> annotation;
077
078                // Optional
079                private Comparator<Field> comparator = FieldNameComparator.INSTANCE;
080
081                public Builder(Class<?> type, Class<? extends Annotation> annotation) {
082                        this.type = type;
083                        this.annotation = annotation;
084                }
085
086                public Builder comparator(Comparator<Field> comparator) {
087                        this.comparator = comparator;
088                        return this;
089                }
090
091                @Override
092                public AnnotatedFieldAssembler build() {
093                        AnnotatedFieldAssembler instance = new AnnotatedFieldAssembler(this);
094                        validate(instance);
095                        return instance;
096                }
097
098                private static void validate(AnnotatedFieldAssembler instance) {
099                        checkNotNull(instance.annotation, "'annotation' cannot be null");
100                        checkNotNull(instance.type, "'type' cannot be null");
101                        checkNotNull(instance.comparator, "'comparator' cannot be null");
102                }
103
104                public Comparator<Field> getComparator() {
105                        return comparator;
106                }
107
108                public void setComparator(Comparator<Field> comparator) {
109                        this.comparator = comparator;
110                }
111
112                public Class<? extends Annotation> getAnnotation() {
113                        return annotation;
114                }
115
116                public Class<?> getType() {
117                        return type;
118                }
119        }
120
121        public Class<? extends Annotation> getAnnotation() {
122                return annotation;
123        }
124
125        public Class<?> getType() {
126                return type;
127        }
128
129        public Comparator<Field> getComparator() {
130                return comparator;
131        }
132
133}