source: java/main/src/main/java/com/framsticks/params/FramsClassBuilder.java @ 87

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

HIGHLIGHTS:

  • FramsClass? and contained Param are now immutable classes (like String),

which allows to refer to them concurrently without synchronization
(which for example in turn simplifies GUI management)

  • also make Path immutable (which was earlier only assumed)
  • add global cache for FramsClasses? created solely and automatically

on base of Java classes.

representations basing on given FramsClass?

  • above changes greatly improved GUI responsivness during browsing
  • furtherly improve Param class hierarchy
  • allow to inject actions on state changes into MultiParamLoader?
  • add more tests

CHANGELOG:

Add StatusListener? to MultiParamLoader?.

Minor refactorization in MultiParamLoader?.

First step with auto append.

Add SchemaTest?.

Improve Registry.

Clean up in Registry.

Work out Registry.

Use annotations for Param.

Fix ListChange?.

Improve fluent interface of the FramsClassBuilder?.

Done caching of ReflectionAccess?.Backend

Fix hashCode of Pair.

A step on a way to cache ReflectionAccess?.Backend

Make SimpleAbstractAccess?.framsClass a final field.

Add static cache for FramsClasses? based on java.

Only classes created strictly and automatically
based on java classes are using this cache.

Make all Params immutable.

Many improvement to make Param immutable.

Make PrimitiveParam? generic type.

Several changes to make Param immutable.

Make FramsClass? immutable.

Another improvement to Path immutability.

Several improvements to Path.

Improve PathTest?.

Configurarable MutabilityDetector?.

File size: 7.4 KB
Line 
1package com.framsticks.params;
2
3import java.io.InputStream;
4import java.lang.reflect.Field;
5import java.lang.reflect.Member;
6import java.lang.reflect.Method;
7import java.lang.reflect.ParameterizedType;
8import java.lang.reflect.Type;
9import java.util.ArrayList;
10import java.util.Collections;
11import java.util.HashMap;
12import java.util.LinkedList;
13import java.util.List;
14import java.util.Map;
15
16import org.apache.log4j.Logger;
17
18import com.framsticks.params.annotations.AutoAppendAnnotation;
19import com.framsticks.params.annotations.FramsClassAnnotation;
20import com.framsticks.params.annotations.ParamAnnotation;
21import com.framsticks.parsers.FileSource;
22import com.framsticks.parsers.Loaders;
23import com.framsticks.util.lang.Strings;
24
25@FramsClassAnnotation(id = "class", name = "class")
26public class FramsClassBuilder {
27        private static final Logger log =
28                Logger.getLogger(FramsClassBuilder.class);
29
30        public static String getName(FramsClassAnnotation fca, Class<?> javaClass) {
31                return fca.name().equals("") ? javaClass.getSimpleName() : fca.name();
32        }
33
34        public static String getId(FramsClassAnnotation fca, Class<?> javaClass) {
35                return fca.id().equals("") ? javaClass.getSimpleName() : fca.id();
36        }
37
38        public static String getParamTypeForNativeType(Type type) {
39                if (type instanceof ParameterizedType) {
40                        ParameterizedType p = (ParameterizedType) type;
41                        Type rawType = p.getRawType();
42                        Type containedType = null;
43                        //TODO make implementation here
44                        boolean map = false;
45                        if (rawType.equals(Map.class)) {
46                                containedType = p.getActualTypeArguments()[1];
47                                map = true;
48                        } else if (rawType.equals(List.class)) {
49                                containedType = p.getActualTypeArguments()[0];
50                        }
51                        if (!(containedType instanceof Class)) {
52                                return null;
53                        }
54                        Class<?> containedClass = (Class<?>) containedType;
55                        StringBuilder b = new StringBuilder();
56                        b.append("l ");
57                        FramsClassAnnotation fca = containedClass.getAnnotation(FramsClassAnnotation.class);
58                        if (fca == null) {
59                                log.error("the class is not annotated: " + containedClass);
60                                return null;
61                        }
62                        b.append(getName(fca, containedClass));
63                        if (map) {
64                                b.append(" name");
65                        }
66
67                        return b.toString();
68                }
69
70                if (type instanceof Class) {
71
72                        Class<?> cl = (Class<?>) type;
73
74                        // TODO: future support for enum
75                        // if (cl.isEnum()) {
76                        //      Class<? extends Enum<?>> enumType = (Class<? extends Enum<?>>) cl;
77                        //      Enum<?>[] enums = enumType.getEnumConstants();
78                        //      StringBuilder b = new StringBuilder();
79
80                        //      b.append("d 0 ").append(enums.length - 1).append(" 0 ");
81                        //      for (Enum<?> e : enums) {
82                        //              b.append("~").append(e.name());
83                        //      }
84                        //      return b.toString();
85                        // }
86                        if (cl.equals(Integer.class) || cl.equals(int.class)) {
87                                return "d";
88                        }
89                        if (cl.equals(String.class)) {
90                                return "s";
91                        }
92                        if (cl.equals(Double.class) || cl.equals(double.class)) {
93                                return "f";
94                        }
95                        if (cl.equals(Boolean.class) || cl.equals(boolean.class)) {
96                                return "d 0 1";
97                        }
98                        if (cl.equals(Object.class)) {
99                                return "x";
100                        }
101
102                        return "o " + ((Class<?>) type).getCanonicalName();
103                }
104
105                throw new ConstructionException().msg("failed to find framsticks for native type").arg("type", type);
106        }
107
108        public static final String GENERATE_HELP_PREFIX = "automatically generated from: ";
109
110        public static FramsClass readFromStream(InputStream stream) {
111                return Loaders.loadFramsClass(new FileSource(stream));
112        }
113
114        // public static Class<? extends Param> getParamType(@Nonnull Class<?> c) {
115        //      if (c.equals(Integer.class)) {
116        //              return DecimalParam.class;
117        //      }
118        //      if (c.equals(Double.class)) {
119        //              return FloatParam.class;
120        //      }
121        //      if (c.equals(String.class)) {
122        //              return StringParam.class;
123        //      }
124        //      if (c.equals(Object.class)) {
125        //              return UniversalParam.class;
126        //      }
127        //      return null;
128        // }
129
130        public static String extractIdOf(Member member) {
131                if (member instanceof Field) {
132                        return member.getName();
133                }
134                if (member instanceof Method) {
135                        Method m = (Method) member;
136                        String n = m.getName();
137                        int argsNum = m.getParameterTypes().length;
138                        if (argsNum == 0) {
139                                return n.startsWith("get") ? Strings.uncapitalize(n.substring(3)) : n;
140                        }
141                        if (argsNum == 1) {
142                                return n.startsWith("set") ? Strings.uncapitalize(n.substring(3)) : n;
143                        }
144                        log.error("invalid number of arguments");
145                        return null;
146                }
147                log.error("invalid kind of member");
148                return null;
149        }
150        public static String getName(ParamAnnotation annotation, Member member) {
151                return annotation.name().equals("") ? Strings.capitalize(extractIdOf(member)) : annotation.name();
152        }
153
154        public static String getId(ParamAnnotation annotation, Member member) {
155                return annotation.id().equals("") ? extractIdOf(member) : annotation.id();
156        }
157
158        public static ParamBuilder fill(ParamBuilder builder, Member member, ParamAnnotation annotation) {
159                return builder
160                        .id(getId(annotation, member))
161                        .name(getName(annotation, member));
162
163        }
164
165        public static Map<Class<?>, FramsClass> synchronizedCacheForBasedOnForJavaClass = Collections.synchronizedMap(new HashMap<Class<?>, FramsClass>());
166
167        public FramsClass forClass(Class<?> javaClass) throws ConstructionException {
168                FramsClass result = synchronizedCacheForBasedOnForJavaClass.get(javaClass);
169                if (result != null) {
170                        return result;
171                }
172
173                log.info("building for class " + javaClass);
174
175                FramsClassAnnotation fca = javaClass.getAnnotation(FramsClassAnnotation.class);
176                if (fca == null) {
177                        throw new ConstructionException().msg("java class is not annotated with FramsClassAnnotation").arg("java", javaClass);
178                }
179
180                id(getId(fca, javaClass));
181                name(getName(fca, javaClass));
182
183                Map<String, ParamCandidate> candidates = ParamCandidate.getAllCandidates(javaClass);
184
185                for (ParamCandidate pc : candidates.values()) {
186                        param(Param.build().id(pc.getId()).name(pc.getName()).type(getParamTypeForNativeType(pc.getType())).flags(pc.getFlags()));
187                }
188
189                result = finish();
190
191                synchronizedCacheForBasedOnForJavaClass.put(javaClass, result);
192
193                return result;
194        }
195
196
197        protected String id;
198
199        protected String name;
200
201        protected String description;
202
203        protected final List<Param> params = new LinkedList<>();
204
205        protected List<Group> groups = new ArrayList<Group>();
206
207        @ParamAnnotation
208        public FramsClassBuilder id(String id) {
209                this.id = id;
210                return this;
211        }
212
213        @ParamAnnotation
214        public FramsClassBuilder name(String name) {
215                this.name = name;
216                return this;
217        }
218
219        public FramsClassBuilder idAndName(String v) {
220                this.id = v;
221                this.name = v;
222                return this;
223        }
224
225        @ParamAnnotation(id = "desc")
226        public FramsClassBuilder description(String description) {
227                this.description = description;
228                return this;
229        }
230
231        public FramsClassBuilder() {
232        }
233
234        public FramsClass finish() {
235                return new FramsClass(id, name, description, params, groups);
236        }
237
238        public FramsClassBuilder append(Param param) {
239                params.add(param);
240                return this;
241        }
242
243        @AutoAppendAnnotation
244        public FramsClassBuilder param(ParamBuilder builder) {
245                return append(builder.finish());
246        }
247
248        @AutoAppendAnnotation
249        public FramsClassBuilder group(Group group) {
250                groups.add(group);
251                return this;
252        }
253
254        /**
255         * @return the id
256         */
257        @ParamAnnotation
258        public String getId() {
259                return id;
260        }
261
262        /**
263         * @return the name
264         */
265        @ParamAnnotation
266        public String getName() {
267                return name;
268        }
269
270        /**
271         * @return the description
272         */
273        @ParamAnnotation(id = "desc")
274        public String getDescription() {
275                return description;
276        }
277
278        public FramsClassBuilder group(String group) {
279                return group(new Group(group));
280        }
281
282        public ParamBuilder param(String id) {
283                return new ParamBuilder(this).id(id);
284        }
285
286}
Note: See TracBrowser for help on using the repository browser.