001: /*
002: * Distributed as part of c3p0 v.0.9.1.2
003: *
004: * Copyright (C) 2005 Machinery For Change, Inc.
005: *
006: * Author: Steve Waldman <swaldman@mchange.com>
007: *
008: * This library is free software; you can redistribute it and/or modify
009: * it under the terms of the GNU Lesser General Public License version 2.1, as
010: * published by the Free Software Foundation.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public License
018: * along with this software; see the file LICENSE. If not, write to the
019: * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020: * Boston, MA 02111-1307, USA.
021: */
022:
023: package com.mchange.v2.codegen.bean;
024:
025: import java.io.*;
026: import java.util.*;
027: import com.mchange.v2.log.*;
028: import java.lang.reflect.Modifier;
029: import com.mchange.v1.lang.ClassUtils;
030: import com.mchange.v2.codegen.CodegenUtils;
031: import com.mchange.v2.codegen.IndentedWriter;
032:
033: public class SimplePropertyBeanGenerator implements
034: PropertyBeanGenerator {
035: private final static MLogger logger = MLog
036: .getLogger(SimplePropertyBeanGenerator.class);
037:
038: private boolean inner = false;
039: private int java_version = 130; //1.3.0
040: private boolean force_unmodifiable = false;
041: private String generatorName = this .getClass().getName();
042:
043: // helper vars for generate method
044: protected ClassInfo info;
045: protected Property[] props;
046: protected IndentedWriter iw;
047:
048: protected Set generalImports;
049: protected Set specificImports;
050: protected Set interfaceNames;
051:
052: protected Class super classType;
053: protected List interfaceTypes;
054: protected Class[] propertyTypes;
055:
056: protected List generatorExtensions = new ArrayList();
057:
058: public synchronized void setInner(boolean inner) {
059: this .inner = inner;
060: }
061:
062: public synchronized boolean isInner() {
063: return inner;
064: }
065:
066: /**
067: * @param version a three digit number -- for example Java 1.3.1 is 131
068: */
069: public synchronized void setJavaVersion(int java_version) {
070: this .java_version = java_version;
071: }
072:
073: public synchronized int getJavaVersion() {
074: return java_version;
075: }
076:
077: public synchronized void setGeneratorName(String generatorName) {
078: this .generatorName = generatorName;
079: }
080:
081: public synchronized String getGeneratorName() {
082: return generatorName;
083: }
084:
085: public synchronized void setForceUnmodifiable(
086: boolean force_unmodifiable) {
087: this .force_unmodifiable = force_unmodifiable;
088: }
089:
090: public synchronized boolean isForceUnmodifiable() {
091: return force_unmodifiable;
092: }
093:
094: public synchronized void addExtension(GeneratorExtension ext) {
095: generatorExtensions.add(ext);
096: }
097:
098: public synchronized void removeExtension(GeneratorExtension ext) {
099: generatorExtensions.remove(ext);
100: }
101:
102: public synchronized void generate(ClassInfo info, Property[] props,
103: Writer w) throws IOException {
104: this .info = info;
105: this .props = props;
106: Arrays.sort(props, BeangenUtils.PROPERTY_COMPARATOR);
107: this .iw = (w instanceof IndentedWriter ? (IndentedWriter) w
108: : new IndentedWriter(w));
109:
110: this .generalImports = new TreeSet();
111: if (info.getGeneralImports() != null)
112: generalImports.addAll(Arrays.asList(info
113: .getGeneralImports()));
114:
115: this .specificImports = new TreeSet();
116: if (info.getSpecificImports() != null)
117: specificImports.addAll(Arrays.asList(info
118: .getSpecificImports()));
119:
120: this .interfaceNames = new TreeSet();
121: if (info.getInterfaceNames() != null)
122: interfaceNames.addAll(Arrays.asList(info
123: .getInterfaceNames()));
124:
125: addInternalImports();
126: addInternalInterfaces();
127:
128: resolveTypes();
129:
130: if (!inner) {
131: writeHeader();
132: iw.println();
133: }
134:
135: writeClassDeclaration();
136: iw.println('{');
137: iw.upIndent();
138:
139: writeCoreBody();
140:
141: iw.downIndent();
142: iw.println('}');
143: }
144:
145: protected void resolveTypes() {
146: String[] gen = (String[]) generalImports
147: .toArray(new String[generalImports.size()]);
148: String[] spc = (String[]) specificImports
149: .toArray(new String[specificImports.size()]);
150:
151: if (info.getSuperclassName() != null) {
152: try {
153: super classType = ClassUtils.forName(info
154: .getSuperclassName(), gen, spc);
155: } catch (Exception e) {
156: // System.err.println("WARNING: " + this.getClass().getName() + " could not resolve " +
157: // "superclass '" + info.getSuperclassName() + "'.");
158: if (logger.isLoggable(MLevel.WARNING))
159: logger.warning(this .getClass().getName()
160: + " could not resolve superclass '"
161: + info.getSuperclassName() + "'.");
162:
163: super classType = null;
164: }
165: }
166:
167: interfaceTypes = new ArrayList(interfaceNames.size());
168: for (Iterator ii = interfaceNames.iterator(); ii.hasNext();) {
169: String name = (String) ii.next();
170: try {
171: interfaceTypes.add(ClassUtils.forName(name, gen, spc));
172: } catch (Exception e) {
173: // System.err.println("WARNING: " + this.getClass().getName() + " could not resolve " +
174: // "interface '" + name + "'.");
175:
176: if (logger.isLoggable(MLevel.WARNING))
177: logger.warning(this .getClass().getName()
178: + " could not resolve interface '" + name
179: + "'.");
180:
181: interfaceTypes.add(null);
182: }
183: }
184:
185: propertyTypes = new Class[props.length];
186: for (int i = 0, len = props.length; i < len; ++i) {
187: String name = props[i].getSimpleTypeName();
188: try {
189: propertyTypes[i] = ClassUtils.forName(name, gen, spc);
190: } catch (Exception e) {
191: // e.printStackTrace();
192: // System.err.println("WARNING: " + this.getClass().getName() + " could not resolve " +
193: // "property type '" + name + "'.");
194:
195: if (logger.isLoggable(MLevel.WARNING))
196: logger.log(MLevel.WARNING, this .getClass()
197: .getName()
198: + " could not resolve property type '"
199: + name + "'.", e);
200:
201: propertyTypes[i] = null;
202: }
203: }
204: }
205:
206: protected void addInternalImports() {
207: if (boundProperties()) {
208: specificImports.add("java.beans.PropertyChangeEvent");
209: specificImports.add("java.beans.PropertyChangeSupport");
210: specificImports.add("java.beans.PropertyChangeListener");
211: }
212: if (constrainedProperties()) {
213: specificImports.add("java.beans.PropertyChangeEvent");
214: specificImports.add("java.beans.PropertyVetoException");
215: specificImports.add("java.beans.VetoableChangeSupport");
216: specificImports.add("java.beans.VetoableChangeListener");
217: }
218:
219: for (Iterator ii = generatorExtensions.iterator(); ii.hasNext();) {
220: GeneratorExtension ge = (GeneratorExtension) ii.next();
221: specificImports.addAll(ge.extraSpecificImports());
222: generalImports.addAll(ge.extraGeneralImports());
223: }
224: }
225:
226: protected void addInternalInterfaces() {
227: for (Iterator ii = generatorExtensions.iterator(); ii.hasNext();) {
228: GeneratorExtension ge = (GeneratorExtension) ii.next();
229: interfaceNames.addAll(ge.extraInterfaceNames());
230: }
231: }
232:
233: protected void writeCoreBody() throws IOException {
234: writeJavaBeansChangeSupport();
235: writePropertyVariables();
236: writeOtherVariables();
237: iw.println();
238:
239: writeGetterSetterPairs();
240: if (boundProperties()) {
241: iw.println();
242: writeBoundPropertyEventSourceMethods();
243: }
244: if (constrainedProperties()) {
245: iw.println();
246: writeConstrainedPropertyEventSourceMethods();
247: }
248: writeInternalUtilityFunctions();
249: writeOtherFunctions();
250:
251: writeOtherClasses();
252:
253: String[] completed_intfc_names = (String[]) interfaceNames
254: .toArray(new String[interfaceNames.size()]);
255: String[] completed_gen_imports = (String[]) generalImports
256: .toArray(new String[generalImports.size()]);
257: String[] completed_spc_imports = (String[]) specificImports
258: .toArray(new String[specificImports.size()]);
259: ClassInfo completedClassInfo = new SimpleClassInfo(info
260: .getPackageName(), info.getModifiers(), info
261: .getClassName(), info.getSuperclassName(),
262: completed_intfc_names, completed_gen_imports,
263: completed_spc_imports);
264: for (Iterator ii = generatorExtensions.iterator(); ii.hasNext();) {
265: GeneratorExtension ext = (GeneratorExtension) ii.next();
266: iw.println();
267: ext.generate(completedClassInfo, super classType, props,
268: propertyTypes, iw);
269: }
270: }
271:
272: protected void writeInternalUtilityFunctions() throws IOException {
273: iw
274: .println("private boolean eqOrBothNull( Object a, Object b )");
275: iw.println("{");
276: iw.upIndent();
277:
278: iw.println("return");
279: iw.upIndent();
280: iw.println("a == b ||");
281: iw.println("(a != null && a.equals(b));");
282: iw.downIndent();
283:
284: iw.downIndent();
285: iw.println("}");
286: }
287:
288: protected void writeConstrainedPropertyEventSourceMethods()
289: throws IOException {
290: iw
291: .println("public void addVetoableChangeListener( VetoableChangeListener vcl )");
292: iw.println("{ vcs.addVetoableChangeListener( vcl ); }");
293: iw.println();
294:
295: iw
296: .println("public void removeVetoableChangeListener( VetoableChangeListener vcl )");
297: iw.println("{ vcs.removeVetoableChangeListener( vcl ); }");
298: iw.println();
299:
300: if (java_version >= 140) {
301: iw
302: .println("public VetoableChangeListener[] getVetoableChangeListeners()");
303: iw.println("{ return vcs.getPropertyChangeListeners(); }");
304: }
305: }
306:
307: protected void writeBoundPropertyEventSourceMethods()
308: throws IOException {
309: iw
310: .println("public void addPropertyChangeListener( PropertyChangeListener pcl )");
311: iw.println("{ pcs.addPropertyChangeListener( pcl ); }");
312: iw.println();
313:
314: iw
315: .println("public void addPropertyChangeListener( String propName, PropertyChangeListener pcl )");
316: iw
317: .println("{ pcs.addPropertyChangeListener( propName, pcl ); }");
318: iw.println();
319:
320: iw
321: .println("public void removePropertyChangeListener( PropertyChangeListener pcl )");
322: iw.println("{ pcs.removePropertyChangeListener( pcl ); }");
323: iw.println();
324:
325: iw
326: .println("public void removePropertyChangeListener( String propName, PropertyChangeListener pcl )");
327: iw
328: .println("{ pcs.removePropertyChangeListener( propName, pcl ); }");
329: iw.println();
330:
331: if (java_version >= 140) {
332: iw
333: .println("public PropertyChangeListener[] getPropertyChangeListeners()");
334: iw.println("{ return pcs.getPropertyChangeListeners(); }");
335: }
336: }
337:
338: protected void writeJavaBeansChangeSupport() throws IOException {
339: if (boundProperties()) {
340: iw
341: .println("protected PropertyChangeSupport pcs = new PropertyChangeSupport( this );");
342: iw.println();
343: iw
344: .println("protected PropertyChangeSupport getPropertyChangeSupport()");
345: iw.println("{ return pcs; }");
346:
347: }
348: if (constrainedProperties()) {
349: iw
350: .println("protected VetoableChangeSupport vcs = new VetoableChangeSupport( this );");
351: iw.println();
352: iw
353: .println("protected VetoableChangeSupport getVetoableChangeSupport()");
354: iw.println("{ return vcs; }");
355: }
356: }
357:
358: protected void writeOtherVariables() throws IOException //hook method for subclasses
359: {
360: }
361:
362: protected void writeOtherFunctions() throws IOException //hook method for subclasses
363: {
364: }
365:
366: protected void writeOtherClasses() throws IOException //hook method for subclasses
367: {
368: }
369:
370: protected void writePropertyVariables() throws IOException {
371: for (int i = 0, len = props.length; i < len; ++i)
372: writePropertyVariable(props[i]);
373: }
374:
375: protected void writePropertyVariable(Property prop)
376: throws IOException {
377: BeangenUtils.writePropertyVariable(prop, iw);
378: // iw.print( CodegenUtils.getModifierString( prop.getVariableModifiers() ) );
379: // iw.print( ' ' + prop.getSimpleTypeName() + ' ' + prop.getName());
380: // String dflt = prop.getDefaultValueExpression();
381: // if (dflt != null)
382: // iw.print( " = " + dflt );
383: // iw.println(';');
384: }
385:
386: /**
387: * @deprecated
388: */
389: protected void writePropertyMembers() throws IOException {
390: throw new InternalError(
391: "writePropertyMembers() deprecated and removed. please us writePropertyVariables().");
392: }
393:
394: /**
395: * @deprecated
396: */
397: protected void writePropertyMember(Property prop)
398: throws IOException {
399: throw new InternalError(
400: "writePropertyMember() deprecated and removed. please us writePropertyVariable().");
401: }
402:
403: protected void writeGetterSetterPairs() throws IOException {
404: for (int i = 0, len = props.length; i < len; ++i) {
405: writeGetterSetterPair(props[i], propertyTypes[i]);
406: if (i != len - 1)
407: iw.println();
408: }
409: }
410:
411: protected void writeGetterSetterPair(Property prop, Class propType)
412: throws IOException {
413: writePropertyGetter(prop, propType);
414:
415: if (!prop.isReadOnly() && !force_unmodifiable) {
416: iw.println();
417: writePropertySetter(prop, propType);
418: }
419: }
420:
421: protected void writePropertyGetter(Property prop, Class propType)
422: throws IOException {
423: BeangenUtils.writePropertyGetter(prop, this
424: .getGetterDefensiveCopyExpression(prop, propType), iw);
425:
426: // String pfx = ("boolean".equals( prop.getSimpleTypeName() ) ? "is" : "get" );
427: // iw.print( CodegenUtils.getModifierString( prop.getGetterModifiers() ) );
428: // iw.println(' ' + prop.getSimpleTypeName() + ' ' + pfx + BeangenUtils.capitalize( prop.getName() ) + "()");
429: // String retVal = getGetterDefensiveCopyExpression( prop, propType );
430: // if (retVal == null) retVal = prop.getName();
431: // iw.println("{ return " + retVal + "; }");
432: }
433:
434: // boolean changeMarked( Property prop )
435: // { return prop.isBound() || prop.isConstrained(); }
436:
437: protected void writePropertySetter(Property prop, Class propType)
438: throws IOException {
439: BeangenUtils.writePropertySetter(prop, this
440: .getSetterDefensiveCopyExpression(prop, propType), iw);
441:
442: // iw.print( CodegenUtils.getModifierString( prop.getSetterModifiers() ) );
443: // iw.print(" void set" + BeangenUtils.capitalize( prop.getName() ) + "( " + prop.getSimpleTypeName() + ' ' + prop.getName() + " )");
444: // if ( prop.isConstrained() )
445: // iw.println(" throws PropertyVetoException");
446: // else
447: // iw.println();
448: // String setVal = getSetterDefensiveCopyExpression( prop, propType );
449: // if (setVal == null) setVal = prop.getName();
450: // iw.println('{');
451: // iw.upIndent();
452:
453: // if ( changeMarked( prop ) )
454: // {
455: // iw.println( prop.getSimpleTypeName() + " oldVal = this." + prop.getName() + ';');
456:
457: // String oldValExpr = "oldVal";
458: // String newValExpr = prop.getName();
459: // String changeCheck;
460: // if ( propType != null && propType.isPrimitive() ) //sometimes the type can't be resolved. if so, it ain't primitive.
461: // {
462: // // PropertyChange support already has overrides
463: // // for boolean and int
464: // if (propType == byte.class)
465: // {
466: // oldValExpr = "new Byte( "+ oldValExpr +" )";
467: // newValExpr = "new Byte( "+ newValExpr +" )";
468: // }
469: // else if (propType == char.class)
470: // {
471: // oldValExpr = "new Character( "+ oldValExpr +" )";
472: // newValExpr = "new Character( "+ newValExpr +" )";
473: // }
474: // else if (propType == short.class)
475: // {
476: // oldValExpr = "new Short( "+ oldValExpr +" )";
477: // newValExpr = "new Short( "+ newValExpr +" )";
478: // }
479: // else if (propType == float.class)
480: // {
481: // oldValExpr = "new Float( "+ oldValExpr +" )";
482: // newValExpr = "new Float( "+ newValExpr +" )";
483: // }
484: // else if (propType == double.class)
485: // {
486: // oldValExpr = "new Double( "+ oldValExpr +" )";
487: // newValExpr = "new Double( "+ newValExpr +" )";
488: // }
489:
490: // changeCheck = "oldVal != " + prop.getName();
491: // }
492: // else
493: // changeCheck = "! eqOrBothNull( oldVal, " + prop.getName() + " )";
494:
495: // if ( prop.isConstrained() )
496: // {
497: // iw.println("if ( " + changeCheck + " )");
498: // iw.upIndent();
499: // iw.println("vcs.fireVetoableChange( \"" + prop.getName() + "\", " + oldValExpr + ", " + newValExpr + " );");
500: // iw.downIndent();
501: // }
502:
503: // iw.println("this." + prop.getName() + " = " + setVal + ';');
504:
505: // if ( prop.isBound() )
506: // {
507: // iw.println("if ( " + changeCheck + " )");
508: // iw.upIndent();
509: // iw.println("pcs.firePropertyChange( \"" + prop.getName() + "\", " + oldValExpr + ", " + newValExpr + " );");
510: // iw.downIndent();
511: // }
512: // }
513: // else
514: // iw.println("this." + prop.getName() + " = " + setVal + ';');
515:
516: // iw.downIndent();
517: // iw.println('}');
518: }
519:
520: protected String getGetterDefensiveCopyExpression(Property prop,
521: Class propType) {
522: return prop.getDefensiveCopyExpression();
523: }
524:
525: protected String getSetterDefensiveCopyExpression(Property prop,
526: Class propType) {
527: return prop.getDefensiveCopyExpression();
528: }
529:
530: protected String getConstructorDefensiveCopyExpression(
531: Property prop, Class propType) {
532: return prop.getDefensiveCopyExpression();
533: }
534:
535: protected void writeHeader() throws IOException {
536: writeBannerComments();
537: iw.println();
538: iw.println("package " + info.getPackageName() + ';');
539: iw.println();
540: writeImports();
541: }
542:
543: protected void writeBannerComments() throws IOException {
544: iw.println("/*");
545: iw.println(" * This class autogenerated by " + generatorName
546: + '.');
547: iw.println(" * DO NOT HAND EDIT!");
548: iw.println(" */");
549: }
550:
551: protected void writeImports() throws IOException {
552: for (Iterator ii = generalImports.iterator(); ii.hasNext();)
553: iw.println("import " + ii.next() + ".*;");
554: for (Iterator ii = specificImports.iterator(); ii.hasNext();)
555: iw.println("import " + ii.next() + ";");
556: }
557:
558: protected void writeClassDeclaration() throws IOException {
559: iw.print(CodegenUtils.getModifierString(info.getModifiers())
560: + " class " + info.getClassName());
561: String super className = info.getSuperclassName();
562: if (super className != null)
563: iw.print(" extends " + super className);
564: if (interfaceNames.size() > 0) {
565: iw.print(" implements ");
566: boolean first = true;
567: for (Iterator ii = interfaceNames.iterator(); ii.hasNext();) {
568: if (first)
569: first = false;
570: else
571: iw.print(", ");
572:
573: iw.print((String) ii.next());
574: }
575: }
576: iw.println();
577: }
578:
579: boolean boundProperties() {
580: return BeangenUtils.hasBoundProperties(props);
581: }
582:
583: boolean constrainedProperties() {
584: return BeangenUtils.hasConstrainedProperties(props);
585: }
586:
587: public static void main(String[] argv) {
588: try {
589: ClassInfo info = new SimpleClassInfo("test",
590: Modifier.PUBLIC, argv[0], null, null,
591: new String[] { "java.awt" }, null);
592:
593: Property[] props = {
594: new SimpleProperty("number", "int", null, "7",
595: false, true, false),
596: new SimpleProperty("fpNumber", "float", null, null,
597: true, true, false),
598: new SimpleProperty("location", "Point",
599: "new Point( location.x, location.y )",
600: "new Point( 0, 0 )", false, true, true) };
601:
602: FileWriter fw = new FileWriter(argv[0] + ".java");
603: SimplePropertyBeanGenerator g = new SimplePropertyBeanGenerator();
604: g.addExtension(new SerializableExtension());
605: g.generate(info, props, fw);
606: fw.flush();
607: fw.close();
608: } catch (Exception e) {
609: e.printStackTrace();
610: }
611: }
612: }
|