source: java/main/src/main/java/com/framsticks/params/ParamCandidate.java @ 86

Last change on this file since 86 was 86, checked in by psniegowski, 11 years ago

HIGHLIGHTS:

  • use java annotations to mark classes and fields to be used when:
    • using java classes with ReflectionAccess? to represent remote objects with FramsClass? description found by "info ..." requests
    • to build up FramsClass? representation of objects not present at remote server
  • allow using primitive types (instead of wraping counterparts) in reflected classes
  • rework FramsClass? creation process (add FramsClassBuilder?)
  • add more tests

CHANGELOG:
Prepare model.World class.

Minor change.

Use primitive types for Genotype and Creature classes.

Use primitive types in model.Neuro* classes.

Use primitive types in model.Joint* classes.

Use primitive types in model.Part* classes.

Fix primitive values.

Extract FramsClassBuilder?.

Add tests of Model classes.

More fixes.

Refactorize out ParamCandidate?.

Several fixes.

Fix all regressions after introducing annotations.

Use annotations throughout the project.

Add exception classes.

Improve creation of FramsClass?.

More changes.

Many changes regarding annotations.

Annotate classes in com.framsticks.model package.

Remove manual FramsClass? constructor.

Construct FramsClass? for Creature. Add test.

Add default values to the ParamAnnotation?.

Add ParamBuilderTest? and ParamAnnotation?.

Add FramsClassAnnotation?.

File size: 6.0 KB
Line 
1package com.framsticks.params;
2
3import java.lang.reflect.AnnotatedElement;
4import java.lang.reflect.Array;
5import java.lang.reflect.Field;
6import java.lang.reflect.GenericArrayType;
7import java.lang.reflect.Member;
8import java.lang.reflect.Method;
9import java.lang.reflect.Modifier;
10import java.lang.reflect.ParameterizedType;
11import java.lang.reflect.Type;
12import java.util.Collection;
13import java.util.HashMap;
14import java.util.Map;
15
16import com.framsticks.params.annotations.ParamAnnotation;
17
18public class ParamCandidate {
19
20        public class OneTime<T> {
21                protected final String name;
22                T value;
23
24                /**
25                 * @param name
26                 */
27                public OneTime(String name) {
28                        this.name = name;
29                }
30
31                final void set(T value) {
32                        if (this.value == null) {
33                                this.value = value;
34                                return;
35                        }
36                        if (!this.value.equals(value)) {
37                                throw new ConstructionException().msg("already set")
38                                        .arg("name", name)
39                                        .arg("in", ParamCandidate.this)
40                                        .arg("already", this.value)
41                                        .arg("now", value);
42                        }
43                }
44
45                public final T get() {
46                        return value;
47                }
48
49                public final boolean has() {
50                        return value != null;
51                }
52
53                @Override
54                public String toString() {
55                        return value == null ? "<null>" : value.toString();
56                }
57
58
59        }
60
61        protected final String id;
62        protected final OneTime<String> name = new OneTime<>("name");
63        protected final OneTime<Type> type = new OneTime<>("type");
64        protected final OneTime<Field> field = new OneTime<>("field");
65        protected final OneTime<Method> setter = new OneTime<>("setter");
66        protected final OneTime<Method> getter = new OneTime<>("getter");
67
68        /**
69         * @param id
70         */
71        public ParamCandidate(String id) {
72                this.id = id;
73        }
74
75        /**
76         * @return the id
77         */
78        public String getId() {
79                return id;
80        }
81
82        /**
83         * @return the name
84         */
85        public String getName() {
86                return name.get();
87        }
88
89        /**
90         * @return the type
91         */
92        public Type getType() {
93                return type.get();
94        }
95
96        public Class<?> getRawType() {
97                return getRawClass(type.get());
98        }
99
100        void setType(Type type) {
101                this.type.set(type);
102        }
103
104
105        /**
106         * @return the field
107         */
108        public Field getField() {
109                return field.get();
110        }
111
112        /**
113         * @return the setter
114         */
115        public Method getSetter() {
116                return setter.get();
117        }
118
119        /**
120         * @return the getter
121         */
122        public Method getGetter() {
123                return getter.get();
124        }
125
126        void validate() throws ConstructionException {
127                try {
128                        if (isPublic(field)) {
129                                if (getter.has()) {
130                                        throw new ConstructionException().msg("getter and public field coexist");
131                                }
132                                return;
133                        }
134                        if (field.has()) {
135                                if (setter.has()) {
136                                        throw new ConstructionException().msg("setter and field coexist");
137                                }
138                        }
139
140                        if (getter.get() == null) {
141                                throw new ConstructionException().msg("missing getter");
142                        }
143                } catch (ConstructionException e) {
144                        throw e.arg("in", this);
145                }
146        }
147
148        boolean isFinal() {
149                if (Collection.class.isAssignableFrom(getRawType())) {
150                        return false;
151                }
152                if (setter.has()) {
153                        return false;
154                }
155                if (field.has()) {
156                        return Modifier.isFinal(field.get().getModifiers());
157                }
158                return true;
159        }
160
161        boolean isReadOnly() {
162                if (Collection.class.isAssignableFrom(getRawType())) {
163                        return false;
164                }
165                if (isPublic(setter)) {
166                        return false;
167                }
168                if (isPublic(field)) {
169                        return Modifier.isFinal(field.get().getModifiers());
170                }
171                return true;
172        }
173
174        void add(Member member, String name) {
175                this.name.set(name);
176                if (member instanceof Field) {
177                        this.field.set((Field) member);
178                        setType(field.get().getGenericType());
179                        return;
180                }
181                if (member instanceof Method) {
182                        Method m = (Method) member;
183                        Type[] ps = m.getGenericParameterTypes();
184                        if (ps.length == 0) {
185                                getter.set(m);
186                                setType(m.getGenericReturnType());
187                                return;
188                        }
189                        if (ps.length == 1) {
190                                setter.set(m);
191                                setType(ps[0]);
192                                return;
193                        }
194                        throw new ConstructionException().msg("invalid number of arguments").arg("method", m).arg("in", this);
195                }
196                throw new ConstructionException().msg("invalid kind of member").arg("member", member).arg("in", this);
197        }
198
199        public boolean isPrimitive() {
200                return getRawType().isPrimitive();
201        }
202
203        public int getFlags() {
204                int f = 0;
205                if (isReadOnly()) {
206                        f |= Flags.READONLY;
207                }
208                return f;
209        }
210
211        @Override
212        public String toString() {
213                return id;
214        }
215
216        public static boolean isPublic(Member member) {
217                return Modifier.isPublic(member.getModifiers());
218        }
219
220        public static boolean isPublic(OneTime<? extends Member> v) {
221                return v.has() ? isPublic(v.get()) : false;
222        }
223
224        public static <M extends Member & AnnotatedElement> void filterParamsCandidates(Map<String, ParamCandidate> params, M[] members) {
225                for (M m : members) {
226                        ParamAnnotation pa = m.getAnnotation(ParamAnnotation.class);
227                        if (pa == null) {
228                                continue;
229                        }
230                        // if (!isPublic(m)) {
231                        //      throw new ConstructionException().msg("field is not public").arg("field", m);
232                        // }
233                        String id = FramsClassBuilder.getId(pa, m);
234                        ParamCandidate pc = null;
235                        if (params.containsKey(id)) {
236                                pc = params.get(id);
237                        } else {
238                                pc = new ParamCandidate(id);
239                                params.put(id, pc);
240                        }
241                        pc.add(m, FramsClassBuilder.getName(pa, m));
242
243                }
244        }
245
246        public static Map<String, ParamCandidate> getAllCandidates(Class<?> javaClass) throws ConstructionException {
247                Map<String, ParamCandidate> candidates = new HashMap<>();
248
249                while (javaClass != null) {
250                        filterParamsCandidates(candidates, javaClass.getDeclaredFields());
251                        filterParamsCandidates(candidates, javaClass.getDeclaredMethods());
252
253                        javaClass = javaClass.getSuperclass();
254                }
255
256                for (ParamCandidate pc : candidates.values()) {
257                        pc.validate();
258                }
259
260                return candidates;
261        }
262
263        public static Class<?> getRawClass(final Type type) {
264                if (Class.class.isInstance(type)) {
265                        return Class.class.cast(type);
266                }
267                if (ParameterizedType.class.isInstance(type)) {
268                        final ParameterizedType parameterizedType = ParameterizedType.class.cast(type);
269                        return getRawClass(parameterizedType.getRawType());
270                } else if (GenericArrayType.class.isInstance(type)) {
271                        GenericArrayType genericArrayType = GenericArrayType.class.cast(type);
272                        Class<?> c = getRawClass(genericArrayType.getGenericComponentType());
273                        return Array.newInstance(c, 0).getClass();
274                } else {
275                        return null;
276                }
277        }
278
279};
Note: See TracBrowser for help on using the repository browser.