View Javadoc
1   /*
2    * Redistribution and use of this software and associated documentation ("Software"), with or
3    * without modification, are permitted provided that the following conditions are met:
4    *
5    * 1. Redistributions of source code must retain copyright statements and notices. Redistributions
6    * must also contain a copy of this document.
7    *
8    * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
9    * conditions and the following disclaimer in the documentation and/or other materials provided with
10   * the distribution.
11   *
12   * 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
13   * without prior written permission of Intalio, Inc. For written permission, please contact
14   * info@exolab.org.
15   *
16   * 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
17   * their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
18   * Intalio, Inc.
19   *
20   * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
21   *
22   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
23   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
25   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
29   * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   * Copyright 2004 (C) Intalio, Inc. All Rights Reserved.
32   *
33   * $Id: CastorSourceGenTask.java 6410 2006-11-17 12:06:24Z wguttmn $
34   */
35  package org.castor.anttask;
36  
37  import java.io.File;
38  import java.io.FileInputStream;
39  import java.io.FileNotFoundException;
40  import java.io.IOException;
41  import java.lang.reflect.InvocationTargetException;
42  import java.lang.reflect.Method;
43  import java.util.Properties;
44  import java.util.Vector;
45  
46  import org.apache.tools.ant.BuildException;
47  import org.apache.tools.ant.DirectoryScanner;
48  import org.apache.tools.ant.taskdefs.MatchingTask;
49  import org.apache.tools.ant.types.FileSet;
50  import org.castor.xml.BackwardCompatibilityContext;
51  import org.castor.xml.InternalContext;
52  import org.exolab.castor.builder.SourceGenerator;
53  import org.exolab.castor.builder.binding.ExtendedBinding;
54  import org.exolab.castor.builder.factory.FieldInfoFactory;
55  import org.exolab.castor.xml.XMLException;
56  import org.exolab.castor.xml.schema.Schema;
57  import org.exolab.castor.xml.schema.SchemaContext;
58  import org.exolab.castor.xml.schema.SchemaContextImpl;
59  import org.exolab.castor.xml.schema.reader.Sax2ComponentReader;
60  import org.exolab.castor.xml.schema.reader.SchemaUnmarshaller;
61  import org.exolab.javasource.JClass;
62  import org.xml.sax.InputSource;
63  import org.xml.sax.Parser;
64  import org.xml.sax.SAXException;
65  
66  /**
67   * An <a href="http://ant.apache.org/">Ant</a> task to call the Castor Source Generator. It can be
68   * passed a file, a directory, a Fileset or all three.
69   *
70   * @author <a href="mailto:joel.farquhar@montage-dmc.com">Joel Farquhar</a>
71   * @author <a href="mailto:ferret AT frii DOT com">Bruce Snyder</a>
72   * @author <a href="mailto:wguttmn AT codehaus DOT org">Werner Guttmann</a>
73   * @version $Revision: 6543 $ $Date: 2005-03-05 06:42:06 -0700 (Sat, 05 Mar 2005) $
74   */
75  public final class CastorCodeGenTask extends MatchingTask {
76  
77    /** Message indicating that the method setJdoDescriptorCreation cannot be invoked. */
78    private static final String PROBLEM_SETTING_JDO_DESC =
79        "Problem calling SourceGenerator.setJdoDescriptorCreation: ";
80  
81    /** Msg indicating class descriptor generation has been disabled. */
82    private static final String DISABLE_DESCRIPTORS_MSG = "Disabling generation of Class descriptors";
83  
84    /** Msg indicating marshaling framework code will not be generated. */
85    private static final String DISABLE_MARSHAL_MSG =
86        "Disabling generation of Marshaling framework methods (marshal, unmarshal, validate).";
87  
88    /** Msg indicating that castor-testable code will be generated. */
89    private static final String CASTOR_TESTABLE_MSG =
90        "The generated classes will implement org.exolab.castor.tests.CastorTestable";
91  
92    /** Error message -- invalid line seperator. */
93    private static final String INVALID_LINESEP_MSG =
94        "Invalid value for lineseparator, must be win, unix, or mac.";
95  
96    /** Error message -- no schemas to run code generator on. */
97    private static final String NO_SCHEMA_MSG =
98        "At least one of the file, url or dir attributes, or a fileset element, must be set.";
99  
100   /** Castor XML context - the mother of all. */
101   private InternalContext _internalContext;
102 
103   /** If processing one schema file, this lists the file. */
104   private File _schemaFile = null;
105 
106   /** If processing one schema file from an URL, this lists the file. */
107   private String _schemaURL = null;
108 
109   /** If processing all schemas in a directory, this lists the directory. */
110   private File _schemaDir = null;
111 
112   /** If processing a fileset, this lists the fileset. */
113   private Vector<FileSet> _schemaFilesets = new Vector<>();
114 
115   // Begin Source Generator parameters
116   /** The package that generated code will belong to. */
117   private String _srcpackage;
118 
119   /** The directory that code will be generated into. */
120   private String _todir;
121 
122   /** The directory that resources will be generated into, if specified. */
123   private String _resourcesDirectory;
124 
125   /** Binding file for the code generator. */
126   private String _bindingfile;
127 
128   /** Information about how to generate collections. */
129   private String _types;
130 
131   /** Line seperator to use for generated code. */
132   private String _lineseparator;
133 
134   /** If true, the code generator will be verbose. */
135   private boolean _verbose;
136 
137   /**
138    * If true, non-fatal warnings will be suppressed. Also, existing source files will be silently
139    * overwritten.
140    */
141   private boolean _warnings = true;
142 
143   /** If true, class descriptors will not be generated. */
144   private boolean _nodesc;
145 
146   /** If true, marshaling code will not be generated. */
147   private boolean _nomarshal;
148 
149   /** If true, old Java field naming conventions will be used. */
150   private boolean _useOldFieldNaming = true;
151 
152   /**
153    * If true, a mapping file will be generated (additionally).
154    */
155   private boolean _generateMapping;
156 
157   /** If true, Castor's CTF testable framework code will be generated. */
158   private boolean _testable;
159 
160   /** Whether to generate code for imported schemas, too. */
161   private boolean _generateImportedSchemas;
162 
163   /** Whether to generate SAX-1 compliant code. */
164   private boolean _sax1;
165 
166   /** Whether enumerated type lookup should be performed in a case insensitive manner. */
167   private boolean _caseInsensitive;
168 
169   /** CastorBuilderProperties file. */
170   private String _properties;
171 
172   /** The name conflict strategy to use. */
173   private String _nameConflictStrategy = "warnViaConsoleDialog";
174 
175   /** Name of the automatic clas name conflict strategy to use. */
176   private String _automaticConflictStrategy = "xpath";
177 
178   /** Whether to generate JDO descriptors. */
179   private boolean _generateJdoDescriptors;
180 
181   /**
182    * Mode for printing JClass instances.
183    */
184   private String _jclassPrinterType = "standard";
185 
186   /** SourceGenerator instance. */
187   private SourceGenerator _sgen;
188 
189   /**
190    * No-arg constructor.
191    */
192   public CastorCodeGenTask() {
193     super();
194     _internalContext = new BackwardCompatibilityContext();
195   }
196 
197   /**
198    * Sets the individual schema that will have code generated for it.
199    * 
200    * @param file One schema file.
201    */
202   public void setFile(final File file) {
203     _schemaFile = file;
204   }
205 
206   /**
207    * Sets an URL for one individual schema that will have code generated for it.
208    * 
209    * @param schemaURL URL for one schema file.
210    */
211   public void setSchemaURL(final String schemaURL) {
212     _schemaURL = schemaURL;
213   }
214 
215 
216   /**
217    * Sets the directory such that all schemas in this directory will have code generated for them.
218    * 
219    * @param dir The directory containing schemas to process.
220    */
221   public void setDir(final File dir) {
222     _schemaDir = dir;
223   }
224 
225   /**
226    * Adds a fileset to process that contains schemas to process.
227    * 
228    * @param set An individual file set containing schemas.
229    */
230   public void addFileset(final FileSet set) {
231     _schemaFilesets.add(set);
232   }
233 
234   /**
235    * Sets the package that generated code will belong to.
236    * 
237    * @param pack The package that generated code will belong to.
238    */
239   public void setPackage(final String pack) {
240     _srcpackage = pack;
241   }
242 
243   /**
244    * Sets the directory into which code will be generated.
245    * 
246    * @param dest The directory into which code will be generated.
247    */
248   public void setTodir(final String dest) {
249     _todir = dest;
250   }
251 
252   /**
253    * Sets the directory into which resources will be generated. If not specified, resources will be
254    * generated in the same location as code.
255    * 
256    * @param dest The directory into which resources will be generated.
257    */
258   public void setResourcesDirectory(final String destination) {
259     _resourcesDirectory = destination;
260   }
261 
262   /**
263    * Sets the binding file to be used for code generation.
264    * 
265    * @param bindingfile The binding file to be used for code generation.
266    */
267   public void setBindingfile(final String bindingfile) {
268     _bindingfile = bindingfile;
269   }
270 
271   /**
272    * Sets the line seperator to use for code generation.
273    * 
274    * @param ls The line seperator to use for code generation.
275    */
276   public void setLineseparator(final String ls) {
277     _lineseparator = ls;
278   }
279 
280   /**
281    * Sets the type factory for code generation.
282    * 
283    * @param tf The type factory to use for code generation.
284    */
285   public void setTypes(final String tf) {
286     _types = "j2".equals(tf) ? "arraylist" : tf;
287   }
288 
289   /**
290    * Sets whether or not code generation gives extra information about its work.
291    * 
292    * @param b If true, the code generator will be verbose.
293    */
294   public void setVerbose(final boolean b) {
295     _verbose = b;
296   }
297 
298   /**
299    * Sets the name conflict strategy to use.
300    * 
301    * @param nameConflictStrategy The name conflict strategy to use
302    */
303   public void setNameConflictStrategy(final String nameConflictStrategy) {
304     _nameConflictStrategy = nameConflictStrategy;
305   }
306 
307   /**
308    * Sets the name conflict strategy to use.
309    * 
310    * @param automaticConflictStrategy The automatic class name conflict strategy to use
311    */
312   public void setAutomaticConflictStrategy(final String automaticConflictStrategy) {
313     _automaticConflictStrategy = automaticConflictStrategy;
314   }
315 
316 
317   /**
318    * Sets whether or not non-fatal warnings should be suppressed.
319    * 
320    * @param b If true, non-fatal warnings will be suppressed. This additionally means that existing
321    *        source files will be silently overwritten.
322    */
323   public void setWarnings(final boolean b) {
324     _warnings = b;
325   }
326 
327   /**
328    * Sets whether or not the old Java field naming conventions should be used.
329    * 
330    * @param useOldFieldNaming If true, the old Java field naming conventions will be used.
331    */
332   public void setUseOldFieldNaming(final boolean useOldFieldNaming) {
333     _useOldFieldNaming = useOldFieldNaming;
334   }
335 
336   /**
337    * Sets whether or not class descriptors are generated.
338    * 
339    * @param b If true, class descriptors are generated.
340    */
341   public void setNodesc(final boolean b) {
342     _nodesc = b;
343   }
344 
345   /**
346    * Sets whether or not marshaling methods are generated.
347    * 
348    * @param b If true, marshaling methods are generated.
349    */
350   public void setNomarshal(final boolean b) {
351     _nomarshal = b;
352   }
353 
354   /**
355    * Sets whether CTF framework code is generated.
356    * 
357    * @param b If true, the generated code will be instrumented for the CTF.
358    */
359   public void setTestable(final boolean b) {
360     _testable = b;
361   }
362 
363   /**
364    * Controls whether to generate code for imported schemas as well.
365    * 
366    * @param generateImportedSchemas True if code should be generated for imported schemas.
367    */
368   public void setGenerateImportedSchemas(final boolean generateImportedSchemas) {
369     _generateImportedSchemas = generateImportedSchemas;
370   }
371 
372   /**
373    * Controls whether to generate JDO-specific class descriptors.
374    * 
375    * @param generateJdoDescriptors True if JDP class descriptors should be generated
376    */
377   public void setGenerateJdoDescriptors(final boolean generateJdoDescriptors) {
378     _generateJdoDescriptors = generateJdoDescriptors;
379   }
380 
381 
382   /**
383    * Controls whether to generate SAX-1 compliant code.
384    * 
385    * @param sax1 True if SAX-1 compliant code should be generated.
386    */
387   public void setSAX1(final boolean sax1) {
388     _sax1 = sax1;
389   }
390 
391   /**
392    * Controls whether enumerated type lookup should be performed in a case insensitive manner.
393    * 
394    * @param caseInsensitive True if enumerated type lookup should be performed in a case insensitive
395    *        manner
396    */
397   public void setCaseInsensitive(final boolean caseInsensitive) {
398     _caseInsensitive = caseInsensitive;
399   }
400 
401   /**
402    * Sets the file to use for castor builder properties.
403    *
404    * @param properties The properties to use.
405    */
406   public void setProperties(final String properties) {
407     _properties = properties;
408   }
409 
410   /**
411    * Sets the mode for printing {@link JClass} instances.
412    * 
413    * @param jclassPrinterType The mode for printing {@link JClass} instances.
414    */
415   public void setJClassPrinterType(final String jclassPrinterType) {
416     _jclassPrinterType = jclassPrinterType;
417   }
418 
419   /**
420    * Controls whether a mapping file should (additionally) be generated.
421    * 
422    * @param generateMapping True if a mapping file should be generated.
423    */
424   public void setGenerateMapping(final boolean generateMapping) {
425     _generateMapping = generateMapping;
426   }
427 
428   /**
429    * Configured the code generator. If anything goes wrong during configuration of the Ant task a
430    * BuildException will be thrown.
431    */
432   private void config() {
433     // Create Source Generator with appropriate type factory
434     if (_types != null) {
435       FieldInfoFactory factory;
436       try {
437         if (_useOldFieldNaming) {
438           factory = new FieldInfoFactory(_types);
439         } else {
440           factory = new FieldInfoFactory(_types, false);
441         }
442 
443         _sgen = new CastorSourceGeneratorWrapper(factory);
444       } catch (Exception e) {
445         try {
446           factory = (FieldInfoFactory) Class.forName(_types).newInstance();
447           _sgen = new CastorSourceGeneratorWrapper(factory);
448         } catch (Exception e2) {
449           throw new BuildException("Invalid types \"" + _types + "\": " + e.getMessage());
450         }
451       }
452     } else {
453       // default
454       _sgen = new CastorSourceGeneratorWrapper();
455     }
456 
457     // Set Line Separator
458     String lineSep = System.getProperty("line.separator");
459     if (_lineseparator != null) {
460       if ("win".equals(_lineseparator)) {
461         log("Using Windows style line separation.");
462         lineSep = "\r\n";
463       } else if ("unix".equals(_lineseparator)) {
464         log("Using UNIX style line separation.");
465         lineSep = "\n";
466       } else if ("mac".equals(_lineseparator)) {
467         log("Using Macintosh style line separation.");
468         lineSep = "\r";
469       } else {
470         throw new BuildException(INVALID_LINESEP_MSG);
471       }
472     }
473     _sgen.setLineSeparator(lineSep);
474 
475     _sgen.setDestDir(_todir);
476 
477     // TODO: use reflection to invoke this
478     if (_resourcesDirectory != null && _resourcesDirectory.length() > 0) {
479       _sgen.setResourceDestination(_resourcesDirectory);
480     }
481 
482     if (_bindingfile != null) {
483       _sgen.setBinding(_bindingfile);
484     }
485 
486     _sgen.setVerbose(_verbose);
487     _sgen.setSuppressNonFatalWarnings(!_warnings);
488 
489     _sgen.setDescriptorCreation(!_nodesc);
490     if (_nodesc) {
491       log(DISABLE_DESCRIPTORS_MSG);
492     }
493 
494     _sgen.setCreateMarshalMethods(!_nomarshal);
495     if (_nomarshal) {
496       log(DISABLE_MARSHAL_MSG);
497     }
498 
499     _sgen.setGenerateImportedSchemas(_generateImportedSchemas);
500 
501     _sgen.setSAX1(_sax1);
502 
503     _sgen.setCaseInsensitive(_caseInsensitive);
504 
505     _sgen.setNameConflictStrategy(_nameConflictStrategy);
506 
507     _sgen.setClassNameConflictResolver(_automaticConflictStrategy);
508 
509     _sgen.setJClassPrinterType(_jclassPrinterType);
510 
511     _sgen.setGenerateMappingFile(_generateMapping);
512 
513     if (_generateJdoDescriptors) {
514       callSetterMethodUsingReflection(_sgen, "setJdoDescriptorCreation", boolean.class,
515           Boolean.valueOf(_generateJdoDescriptors));
516     }
517 
518     _sgen.setTestable(_testable);
519     if (this._testable) {
520       log(CASTOR_TESTABLE_MSG);
521     }
522 
523     // Set Builder Properties;
524     if (_properties != null) {
525       String filePath = new File(_properties).getAbsolutePath();
526       Properties customProperties = new Properties();
527       try (FileInputStream fis = new FileInputStream(filePath)) {
528         customProperties.load(fis);
529       } catch (FileNotFoundException e) {
530         throw new BuildException("Properties file \"" + filePath + "\" not found");
531       } catch (IOException e) {
532         throw new BuildException("Can't read properties file \"" + filePath + "\": " + e);
533       }
534       _sgen.setDefaultProperties(customProperties);
535     }
536   }
537 
538   /**
539    * Runs source generation. If anything goes wrong during source generation a BuildException will
540    * be thrown.
541    * 
542    * @param filePath an individual Schema to generate code for.
543    */
544   private void processFile(final String filePath) {
545     log("Processing " + filePath);
546     try {
547       _sgen.generateSource(filePath, _srcpackage);
548     } catch (FileNotFoundException e) {
549       String message = "XML Schema file \"" + _schemaFile.getAbsolutePath() + "\" not found.";
550       log(message);
551       throw new BuildException(message);
552     } catch (Exception iox) {
553       throw new BuildException(iox);
554     }
555   }
556 
557   /**
558    * Runs source generation on a XML schema instance pointed to by an URL. If anything goes wrong
559    * during source generation a BuildException will be thrown.
560    * 
561    * @param schemaURL An URL to an individual XML schema to generate code for.
562    */
563   private void processURL(final String schemaURL) {
564     log("Processing " + schemaURL);
565     try {
566       InputSource inputSource = new InputSource(schemaURL);
567       _sgen.generateSource(inputSource, _srcpackage);
568     } catch (FileNotFoundException e) {
569       String message = "XML Schema file \"" + _schemaURL + "\" not found.";
570       log(message);
571       throw new BuildException(message);
572     } catch (Exception iox) {
573       throw new BuildException(iox);
574     }
575   }
576 
577   /**
578    * Public execute method -- entry point for the Ant task. Loops over all schema that need code
579    * generated and creates needed code generators, then executes them. If anything goes wrong during
580    * execution of the Ant task a BuildException will be thrown.
581    * 
582    * @see org.apache.tools.ant.Task#execute()
583    */
584   public void execute() {
585     // Must have something to run the source generator on
586     if (_schemaFile == null && _schemaDir == null && _schemaFilesets.isEmpty()
587         && _schemaURL == null) {
588       throw new BuildException(NO_SCHEMA_MSG);
589     }
590 
591     try {
592       config();
593 
594       // Run source generator on file
595       if (_schemaFile != null) {
596         processFile(_schemaFile.getAbsolutePath());
597       }
598 
599       // Run source generator on all files in directory
600       if (_schemaDir != null && _schemaDir.exists() && _schemaDir.isDirectory()) {
601         DirectoryScanner ds = this.getDirectoryScanner(_schemaDir);
602 
603         String[] files = ds.getIncludedFiles();
604         for (String file : files) {
605           String filePath = _schemaDir.getAbsolutePath() + File.separator + file;
606           processFile(filePath);
607         }
608       }
609 
610       // Run source generator on all files in FileSet
611       for (FileSet fs : _schemaFilesets) {
612         DirectoryScanner ds = fs.getDirectoryScanner(getProject());
613         File subdir = fs.getDir(getProject());
614 
615         String[] files = ds.getIncludedFiles();
616         for (String file : files) {
617           String filePath = subdir.getAbsolutePath() + File.separator + file;
618           processFile(filePath);
619         }
620       }
621 
622       // Run source generator on URL for XML schema
623       if (_schemaURL != null) {
624         processURL(_schemaURL);
625       }
626     } finally {
627       _sgen = null;
628     }
629   }
630 
631   /**
632    * Override Castor's SourceGenerator to inject exception handling. Code based on
633    * castor-0.9.5.3-xml.jar.
634    */
635   private final class CastorSourceGeneratorWrapper extends SourceGenerator {
636     /**
637      * No-arg constructor.
638      */
639     public CastorSourceGeneratorWrapper() {
640       super();
641     }
642 
643     /**
644      * Constructs a source generator with the provided FieldInfoFactory.
645      * 
646      * @param fieldInfoFactory A FieldInfoFactory to use for collections.
647      */
648     public CastorSourceGeneratorWrapper(final FieldInfoFactory fieldInfoFactory) {
649       super(fieldInfoFactory);
650     }
651 
652     /**
653      * Constructs a source generator with the provided FieldInfoFactory and binding file.
654      * 
655      * @param fieldInfoFactory a FieldInfoFactory to use for collections.
656      * @param extendedBinding binding information for the code generator.
657      */
658     public CastorSourceGeneratorWrapper(final FieldInfoFactory fieldInfoFactory,
659         final ExtendedBinding extendedBinding) {
660       super(fieldInfoFactory, extendedBinding);
661     }
662 
663     /**
664      * Generate source. If anything goes wrong during generation of source a BuildException will be
665      * thrown.
666      *
667      * @param source an individual schema to process.
668      * @param packageName the package name for generated code.
669      * 
670      * @see org.exolab.castor.builder.SourceGenerator #generateSource(org.xml.sax.InputSource,
671      *      java.lang.String)
672      */
673     public void generateSource(final InputSource source, final String packageName) {
674       Parser parser = null;
675       try {
676         parser = _internalContext.getParser();
677       } catch (RuntimeException e) {
678         throw new BuildException("Unable to create SAX parser.", e);
679       }
680       if (parser == null) {
681         throw new BuildException("Unable to create SAX parser.");
682       }
683 
684       SchemaContext schemaContext = new SchemaContextImpl();
685       SchemaUnmarshaller schemaUnmarshaller = null;
686       try {
687         schemaUnmarshaller = new SchemaUnmarshaller(schemaContext);
688       } catch (XMLException e) {
689         throw new BuildException("Unable to create schema unmarshaller.", e);
690       }
691 
692       Sax2ComponentReader handler = new Sax2ComponentReader(schemaUnmarshaller);
693       parser.setDocumentHandler(handler);
694       parser.setErrorHandler(handler);
695       try {
696         parser.parse(source);
697       } catch (IOException | SAXException e) {
698         String msg = "Can't read input file " + source.getSystemId() + ".\n" + e;
699         throw new BuildException(msg, e);
700       }
701       Schema schema = schemaUnmarshaller.getSchema();
702       try {
703         generateSource(schema, packageName);
704       } catch (Exception iox) {
705         throw new BuildException(iox);
706       }
707     }
708   }
709 
710   /**
711    * Helper method to invoke a setter method on {@link SourceGenerator} that might not be available
712    * due to a version issue.
713    * 
714    * @param sgen {@link SourceGenerator} instance
715    * @param methodName Name of the method
716    * @param parameterType Type of the method parameter.
717    * @param parameterValue Actual parameter value to be used during method invocation.
718    * @throws BuildException If the method cannot be invoked.
719    */
720   private void callSetterMethodUsingReflection(final SourceGenerator sgen, final String methodName,
721       final Class parameterType, final Object parameterValue) throws BuildException {
722     try {
723       Method method = sgen.getClass().getMethod(methodName, new Class[] {parameterType});
724       method.invoke(sgen, new Object[] {parameterValue});
725     } catch (NoSuchMethodException e) {
726       // unable to find method to configure JDO descriptor creation.
727     } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
728       throw new BuildException(PROBLEM_SETTING_JDO_DESC, e);
729     }
730   }
731 
732 
733 
734 }