001: /*
002: * Created on Sep 22, 2004
003: */
004: package uk.org.ponder.saxalizer.mapping;
005:
006: import java.lang.reflect.Field;
007: import java.lang.reflect.Method;
008: import java.lang.reflect.Modifier;
009: import java.util.HashSet;
010:
011: import uk.org.ponder.saxalizer.DefaultInferrible;
012: import uk.org.ponder.saxalizer.SAMSList;
013: import uk.org.ponder.saxalizer.SAXAccessMethodSpec;
014: import uk.org.ponder.stringutil.Pluralizer;
015: import uk.org.ponder.stringutil.StringList;
016: import uk.org.ponder.stringutil.StringSet;
017: import uk.org.ponder.util.EnumerationConverter;
018: import uk.org.ponder.util.Logger;
019:
020: /**
021: * @author Antranig Basman (antranig@caret.cam.ac.uk)
022: *
023: */
024: public class DefaultMapperInferrer implements SAXalizerMapperInferrer {
025: public void setChainedInferrer(SAXalizerMapperInferrer target) {
026: throw new UnsupportedOperationException(
027: "Cannot chain from default inferrer");
028: // We expect to be the head of the chain
029: }
030:
031: private boolean depluralize = true;
032: private ContainerTypeRegistry containertyperegistry;
033:
034: public void setDepluralize(boolean depluralize) {
035: this .depluralize = depluralize;
036: }
037:
038: public void setContainerTypeRegistry(
039: ContainerTypeRegistry containertyperegistry) {
040: this .containertyperegistry = containertyperegistry;
041: }
042:
043: private HashSet defaultiblemap = new HashSet();
044:
045: public void init() {
046: containertyperegistry.addCollectionType(StringList.class,
047: String.class);
048: containertyperegistry.addCollectionType(StringSet.class,
049: String.class);
050: }
051:
052: public void setDefaultInferrible(Class clazz) {
053: defaultiblemap.add(clazz);
054: }
055:
056: public boolean isDefaultInferrible(Class clazz) {
057: return DefaultInferrible.class.isAssignableFrom(clazz)
058: || defaultiblemap.contains(clazz);
059: }
060:
061: public static int accessorType(Method method) {
062: String methodname = method.getName();
063: if (methodname.length() <= 3)
064: return -1;
065: Class returntype = method.getReturnType();
066: int paramlen = method.getParameterTypes().length;
067: if (methodname.startsWith("get")) {
068: if (paramlen == 0) {
069: return SAXAccessMethodSpec.GET_METHOD;
070: }
071: }
072: if (methodname.startsWith("is")) {
073: if (paramlen == 0
074: && (returntype.equals(Boolean.TYPE) || returntype
075: .equals(Boolean.class))) {
076: return SAXAccessMethodSpec.GET_METHOD;
077: }
078: }
079: if (methodname.startsWith("set")
080: || methodname.startsWith("add")) {
081: if (paramlen == 1 && returntype.equals(Void.TYPE))
082: return SAXAccessMethodSpec.SET_METHOD;
083: }
084: return -1;
085: }
086:
087: // TODO: check that this actually agrees with beans spec!
088: public static String deBean(String methodname) {
089: int plen = methodname.startsWith("is") ? 2 : 3;
090: boolean isupperstart = Character.isUpperCase(methodname
091: .charAt(plen + 1));
092: return (isupperstart ? methodname.charAt(plen) : Character
093: .toLowerCase(methodname.charAt(plen)))
094: + methodname.substring(plen + 1);
095: }
096:
097: public static final String dePluralize(String accessname,
098: Class returntype) {
099: String togo = accessname;
100: if (EnumerationConverter.isEnumerable(returntype)) {
101: return Pluralizer.singularize(accessname);
102: }
103: return togo;
104: }
105:
106: /** Returns an new SAMS object with the given name.
107: * @param tagname
108: * @param clazz The *return* type of the method, hence empty for a set method.
109: * @return
110: */
111: private SAXAccessMethodSpec byXMLNameSafe(SAMSList samslist,
112: String tagname, Class clazz) {
113: // must not fuse get and set at this point! Otherwise there will be
114: // duplicate.
115: SAXAccessMethodSpec spec = new SAXAccessMethodSpec();
116: // depluralise if it is a get method
117: spec.xmlname = depluralize ? dePluralize(tagname, clazz)
118: : tagname;
119:
120: Class containeetype = containertyperegistry
121: .getContaineeType(clazz);
122: if (containeetype != null) {
123: spec.clazz = containeetype;
124: }
125: return spec;
126: }
127:
128: private static boolean isPublicNonStatic(int modifiers) {
129: return Modifier.isPublic(modifiers)
130: && !Modifier.isStatic(modifiers);
131: }
132:
133: public SAXalizerMapperEntry inferEntry(Class clazz,
134: SAXalizerMapperEntry preventry) {
135: SAXalizerMapperEntry togo = preventry == null ? new SAXalizerMapperEntry()
136: : preventry;
137: togo.targetclass = clazz;
138: SAMSList sams = togo.getSAMSList();
139: Method[] methods = clazz.getMethods();
140: // if (Logger.log.isDebugEnabled()) {
141: // Logger.log.debug("Inferring default mapping for " + clazz);
142: // }
143: for (int i = 0; i < methods.length; ++i) {
144: int modifiers = methods[i].getModifiers();
145: if (!isPublicNonStatic(modifiers))
146: continue;
147: String methodname = methods[i].getName();
148: if (methodname.equals("getClass"))
149: continue;
150: int methodtype = accessorType(methods[i]);
151: // if (Logger.log.isDebugEnabled()) {
152: // Logger.log.debug("Method " + methodname + " access type " + methodtype);
153: // }
154: if (methodtype != -1) {
155: String basename = deBean(methodname);
156: SAXAccessMethodSpec spec = byXMLNameSafe(sams,
157: basename, methods[i].getReturnType());
158: if (methodtype == SAXAccessMethodSpec.GET_METHOD) {
159: spec.getmethodname = methodname;
160: } else {
161: spec.setmethodname = methodname;
162: }
163: // if (Logger.log.isDebugEnabled()) {
164: // Logger.log.debug("Method gave access method " + spec);
165: // }
166: spec.xmlname += "*"; // better make everything polymorphic
167: togo.addNonDuplicate(spec);
168: }
169: }
170:
171: Field[] fields = clazz.getFields();
172: for (int i = 0; i < fields.length; ++i) {
173: String fieldname = fields[i].getName();
174: int modifiers = fields[i].getModifiers();
175: if (!isPublicNonStatic(modifiers))
176: continue;
177: SAXAccessMethodSpec spec = byXMLNameSafe(sams, fieldname,
178: fields[i].getType());
179: spec.accesstype = SAXAccessMethodSpec.ACCESS_FIELD;
180: spec.fieldname = fieldname;
181: // if (Logger.log.isDebugEnabled()) {
182: // Logger.log.debug("Field gave access method " + spec);
183: // }
184: spec.xmlname += "*"; // better make everything polymorphic
185: togo.addNonDuplicate(spec);
186: }
187:
188: return togo;
189: }
190:
191: }
|