~ubuntu-branches/ubuntu/quantal/netbeans/quantal

« back to all changes in this revision

Viewing changes to j2ee/persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/JavaPersistenceGenerator.java

  • Committer: Bazaar Package Importer
  • Author(s): Marek Slama
  • Date: 2008-01-29 14:11:22 UTC
  • Revision ID: james.westby@ubuntu.com-20080129141122-fnzjbo11ntghxfu7
Tags: upstream-6.0.1
ImportĀ upstreamĀ versionĀ 6.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 
3
 *
 
4
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 
5
 *
 
6
 * The contents of this file are subject to the terms of either the GNU
 
7
 * General Public License Version 2 only ("GPL") or the Common
 
8
 * Development and Distribution License("CDDL") (collectively, the
 
9
 * "License"). You may not use this file except in compliance with the
 
10
 * License. You can obtain a copy of the License at
 
11
 * http://www.netbeans.org/cddl-gplv2.html
 
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 
13
 * specific language governing permissions and limitations under the
 
14
 * License.  When distributing the software, include this License Header
 
15
 * Notice in each file and include the License file at
 
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 
17
 * particular file as subject to the "Classpath" exception as provided
 
18
 * by Sun in the GPL Version 2 section of the License file that
 
19
 * accompanied this code. If applicable, add the following below the
 
20
 * License Header, with the fields enclosed by brackets [] replaced by
 
21
 * your own identifying information:
 
22
 * "Portions Copyrighted [year] [name of copyright owner]"
 
23
 *
 
24
 * Contributor(s):
 
25
 *
 
26
 * The Original Software is NetBeans. The Initial Developer of the Original
 
27
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 
28
 * Microsystems, Inc. All Rights Reserved.
 
29
 *
 
30
 * If you wish your version of this file to be governed by only the CDDL
 
31
 * or only the GPL Version 2, indicate your decision by adding
 
32
 * "[Contributor] elects to include this software in this distribution
 
33
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 
34
 * single choice of license, a recipient has the option to distribute
 
35
 * your version of this file under either the CDDL, the GPL Version 2 or
 
36
 * to extend the choice of license to its licensees as provided above.
 
37
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 
38
 * Version 2 license, then the option applies only if the new code is
 
39
 * made subject to such option by the copyright holder.
 
40
 */
 
41
 
 
42
package org.netbeans.modules.j2ee.persistence.wizard.fromdb;
 
43
 
 
44
import com.sun.source.tree.*;
 
45
import java.util.HashMap;
 
46
import org.netbeans.api.progress.aggregate.ProgressContributor;
 
47
import org.netbeans.modules.j2ee.persistence.api.metadata.orm.Entity;
 
48
import org.netbeans.modules.j2ee.persistence.api.metadata.orm.Table;
 
49
import org.netbeans.spi.java.classpath.ClassPathProvider;
 
50
import org.openide.filesystems.FileObject;
 
51
import java.io.IOException;
 
52
import java.util.ArrayList;
 
53
import java.util.Collections;
 
54
import java.util.EnumSet;
 
55
import java.util.HashSet;
 
56
import java.util.Iterator;
 
57
import java.util.List;
 
58
import java.util.Map;
 
59
import java.util.Set;
 
60
import java.util.logging.Level;
 
61
import java.util.logging.Logger;
 
62
import javax.lang.model.element.*;
 
63
import javax.lang.model.type.*;
 
64
import org.netbeans.api.java.classpath.ClassPath;
 
65
import org.netbeans.api.java.source.JavaSource;
 
66
import org.netbeans.api.java.source.TreeMaker;
 
67
import org.netbeans.api.java.source.WorkingCopy;
 
68
import org.netbeans.api.project.FileOwnerQuery;
 
69
import org.netbeans.api.project.Project;
 
70
import org.netbeans.modules.j2ee.persistence.util.AbstractTask;
 
71
import org.netbeans.modules.j2ee.persistence.util.GenerationUtils;
 
72
import org.netbeans.modules.j2ee.persistence.dd.persistence.model_1_0.PersistenceUnit;
 
73
import org.netbeans.modules.j2ee.persistence.entitygenerator.CMPMappingModel;
 
74
import org.netbeans.modules.j2ee.persistence.entitygenerator.EntityClass;
 
75
import org.netbeans.modules.j2ee.persistence.entitygenerator.EntityMember;
 
76
import org.netbeans.modules.j2ee.persistence.entitygenerator.RelationshipRole;
 
77
import org.netbeans.modules.j2ee.persistence.provider.InvalidPersistenceXmlException;
 
78
import org.netbeans.modules.j2ee.persistence.provider.ProviderUtil;
 
79
import org.netbeans.modules.j2ee.persistence.unit.PUDataObject;
 
80
import org.netbeans.modules.j2ee.persistence.util.EntityMethodGenerator;
 
81
import org.netbeans.modules.j2ee.persistence.util.JPAClassPathHelper;
 
82
import org.netbeans.modules.j2ee.persistence.wizard.Util;
 
83
import org.openide.WizardDescriptor;
 
84
import org.openide.filesystems.FileUtil;
 
85
import org.openide.util.NbBundle;
 
86
 
 
87
/**
 
88
 * Generator of Java Persistence API ORM classes from DB.
 
89
 *
 
90
 * @author Pavel Buzek, Andrei Badea
 
91
 */
 
92
public class JavaPersistenceGenerator implements PersistenceGenerator {
 
93
 
 
94
    // XXX Javadoc for generated code missing in many places - issue 90302
 
95
    // XXX createToStringMethod() could be moved to GenerationUtils
 
96
    // XXX init() commented out until annotation model is implemented
 
97
 
 
98
    // XXX empty lines in generated hashCode() - issue 90186
 
99
    // XXX comments are lost in method body passed as string - issue 89873
 
100
    // XXX return 0, 1 in generated equals() - issue 90183
 
101
    // XXX empty line in generated equals() - issue 90186
 
102
 
 
103
    private final Map<String, String> entityName2TableName = new HashMap<String, String>();
 
104
 
 
105
    // options (not currently exposed in UI)
 
106
    // field vs. property access
 
107
    private static boolean fieldAccess = true;
 
108
    // named input params for named queries vs. positional params
 
109
    private static boolean genNamedParams = true;
 
110
    // should generated Entity Classes implement Serializable?
 
111
    private static boolean genSerializableEntities = true;
 
112
 
 
113
    private Set<FileObject> result;
 
114
 
 
115
    /**
 
116
     * Specifies whether the generated enties should be added to the first
 
117
     * persistence unit found in the project. Note that this setting only
 
118
     * applies to non-Java EE 5 projects - for Java EE 5 projects the entities
 
119
     * are not added to a PU even if this is true.
 
120
     */
 
121
    private final boolean addToAutoDiscoveredPU;
 
122
 
 
123
    /**
 
124
     * The persistence unit to which the generated entities should
 
125
     * be added.
 
126
     */
 
127
    private PersistenceUnit persistenceUnit;
 
128
 
 
129
    /**
 
130
     * Creates a new instance of JavaPersistenceGenerator. Tries to add the
 
131
     * generated entities to the first persistence unit found (only in non-Java EE 5 projects).
 
132
     */
 
133
    public JavaPersistenceGenerator() {
 
134
        this.persistenceUnit = null;
 
135
        this.addToAutoDiscoveredPU = true;
 
136
    }
 
137
 
 
138
 
 
139
    /**
 
140
     * Creates a new instance of JavaPersistenceGenerator
 
141
     *
 
142
     * @param persistenceUnit the persistence unit to which the generated entities
 
143
     * should be added. Must exist in the project where the entities are generated.
 
144
     * Has no effect in Java EE 5 projects - in those
 
145
     * the entities are not added to any persistence unit regardless of this. May
 
146
     * be null, in which case the generated entities are not added any persistence unit.
 
147
     */
 
148
    public JavaPersistenceGenerator(PersistenceUnit persistenceUnit) {
 
149
        this.persistenceUnit = persistenceUnit;
 
150
        this.addToAutoDiscoveredPU = false;
 
151
    }
 
152
 
 
153
 
 
154
    public void generateBeans(final ProgressPanel progressPanel,
 
155
            final RelatedCMPHelper helper,
 
156
            final FileObject dbSchemaFile,
 
157
            final ProgressContributor handle) throws IOException {
 
158
 
 
159
        generateBeans(helper.getBeans(), helper.isGenerateFinderMethods(), handle, progressPanel);
 
160
    }
 
161
 
 
162
    // package private for tests
 
163
    void generateBeans(EntityClass[] entityClasses,
 
164
            boolean generateNamedQueries, ProgressContributor progressContributor, ProgressPanel panel) throws IOException {
 
165
 
 
166
        int progressMax = entityClasses.length * 2;
 
167
        progressContributor.start(progressMax);
 
168
        result = new Generator(entityClasses, generateNamedQueries, progressContributor, panel).run();
 
169
        addToPersistenceUnit(result);
 
170
        progressContributor.progress(progressMax);
 
171
    }
 
172
 
 
173
    
 
174
    /**
 
175
     * Adds the given entities to out persistence unit found in the project.
 
176
     */
 
177
    private void addToPersistenceUnit(Set<FileObject> entities){
 
178
 
 
179
        if (entities.isEmpty()){
 
180
            return;
 
181
        }
 
182
 
 
183
        if (persistenceUnit == null && !addToAutoDiscoveredPU){
 
184
            return;
 
185
        }
 
186
        
 
187
        Project project = FileOwnerQuery.getOwner(entities.iterator().next());
 
188
        if (project != null && !Util.isSupportedJavaEEVersion(project) && ProviderUtil.getDDFile(project) != null) {
 
189
            try {
 
190
                PUDataObject pudo = ProviderUtil.getPUDataObject(project);
 
191
                // no persistence unit was provider, we'll try find one
 
192
                if (persistenceUnit == null){
 
193
                    PersistenceUnit pu[] = pudo.getPersistence().getPersistenceUnit();
 
194
                    //only add if a PU exists, if there are more we do not know where to add - UI needed to ask
 
195
                    if (pu.length == 1) {
 
196
                        persistenceUnit = pu[0];
 
197
                    }
 
198
                }
 
199
                if (persistenceUnit != null){
 
200
                    ClassPathProvider classPathProvider = project.getLookup().lookup(ClassPathProvider.class);
 
201
                    if (classPathProvider != null) {
 
202
                        for(FileObject entity : entities){
 
203
                            String entityFQN = classPathProvider.findClassPath(entity, ClassPath.SOURCE).getResourceName(entity, '.', false);
 
204
                            pudo.addClass(persistenceUnit, entityFQN);
 
205
                        }
 
206
                    }
 
207
                }
 
208
 
 
209
            } catch (InvalidPersistenceXmlException ipx){
 
210
                // just log for debugging purposes, at this point the user has
 
211
                // already been warned about an invalid persistence.xml
 
212
                Logger.getLogger(JavaPersistenceGenerator.class.getName()).log(Level.FINE, "Invalid persistence.xml: " + ipx.getPath(), ipx); //NO18N
 
213
            }
 
214
        }
 
215
 
 
216
    }
 
217
 
 
218
    public void init(WizardDescriptor wiz) {
 
219
        // get the table names for all entities in the project
 
220
        // Project project = Templates.getProject(wiz);
 
221
        // try {
 
222
        //     processEntities(PersistenceUtils.getEntityClasses(project));
 
223
        // } catch (IOException e) {
 
224
        //     ErrorManager.getDefault().notify(e);
 
225
        // }
 
226
        // processEntities(PersistenceUtils.getAnnotationEntityClasses(project));
 
227
    }
 
228
 
 
229
    private void processEntities(Set<Entity> entityClasses) {
 
230
        for (Entity entity : entityClasses) {
 
231
            Table entityTable = entity.getTable();
 
232
            if (entityTable != null) {
 
233
                entityName2TableName.put(entityTable.getName(), entity.getClass2());
 
234
            }
 
235
        }
 
236
    }
 
237
 
 
238
    public void uninit() {
 
239
    }
 
240
 
 
241
    public String getFQClassName(String tableName) {
 
242
        return entityName2TableName.get(tableName);
 
243
    }
 
244
 
 
245
    public String generateEntityName(String name) {
 
246
        return name;
 
247
    }
 
248
 
 
249
    public Set<FileObject> createdObjects() {
 
250
        return result;
 
251
    }
 
252
 
 
253
 
 
254
    /**
 
255
     * Encapsulates the whole entity class generation process.
 
256
     */
 
257
    private static final class Generator {
 
258
        private final ProgressPanel progressPanel;
 
259
        private final ProgressContributor progressContributor;
 
260
        private final Map<String, EntityClass> beanMap = new HashMap<String, EntityClass>();
 
261
        private final EntityClass[] entityClasses;
 
262
        private final boolean generateNamedQueries;
 
263
        private final Set<FileObject> generatedEntityFOs;
 
264
        private final Set<FileObject> generatedFOs;
 
265
 
 
266
        public Generator(EntityClass[] entityClasses, boolean generateNamedQueries,
 
267
                ProgressContributor progressContributor, ProgressPanel progressPanel) {
 
268
            this.entityClasses = entityClasses;
 
269
            this.generateNamedQueries = generateNamedQueries;
 
270
            this.progressContributor = progressContributor;
 
271
            this.progressPanel = progressPanel;
 
272
            generatedFOs = new HashSet<FileObject>();
 
273
            generatedEntityFOs = new HashSet<FileObject>();
 
274
        }
 
275
 
 
276
        public Set<FileObject> run() throws IOException {
 
277
            try {
 
278
                runImpl();
 
279
            } catch (IOException e) {
 
280
                for (FileObject generatedFO : generatedFOs) {
 
281
                    generatedFO.delete();
 
282
                }
 
283
                throw e;
 
284
            }
 
285
            return generatedEntityFOs;
 
286
        }
 
287
 
 
288
        public void runImpl() throws IOException {
 
289
 
 
290
            // first generate empty entity classes -- this is needed as
 
291
            // in the field and method generation it will be necessary to resolve
 
292
            // their types (e.g. entity A has a field of type Collection<B>, thus
 
293
            // while generating entity A we must be able to resolve type B).
 
294
 
 
295
            beanMap.clear();
 
296
            Set<FileObject> generationPackageFOs = new HashSet<FileObject>();
 
297
            Set<String> generatedEntityClasses = new HashSet<String>();
 
298
 
 
299
            for (int i = 0; i < entityClasses.length; i++) {
 
300
                final EntityClass entityClass = entityClasses[i];
 
301
                String entityClassName = entityClass.getClassName();
 
302
                FileObject packageFileObject = entityClass.getPackageFileObject();
 
303
                beanMap.put(entityClassName, entityClass);
 
304
 
 
305
                if (packageFileObject.getFileObject(entityClassName, "java") != null) { // NOI18N
 
306
                    progressContributor.progress(i);
 
307
                    continue;
 
308
                }
 
309
                String progressMsg = NbBundle.getMessage(JavaPersistenceGenerator.class, "TXT_GeneratingClass", entityClassName);
 
310
 
 
311
                progressContributor.progress(progressMsg, i);
 
312
                if (progressPanel != null){
 
313
                    progressPanel.setText(progressMsg);
 
314
                }
 
315
 
 
316
                generationPackageFOs.add(packageFileObject);
 
317
                generatedEntityClasses.add(entityClassName);
 
318
 
 
319
                // XXX Javadoc
 
320
                FileObject entity = GenerationUtils.createClass(packageFileObject, entityClassName, NbBundle.getMessage(JavaPersistenceGenerator.class, "MSG_Javadoc_Class"));
 
321
                generatedEntityFOs.add(entity);
 
322
                generatedFOs.add(entity);
 
323
                if (!entityClass.isUsePkField()) {
 
324
                    String pkClassName = createPKClassName(entityClassName);
 
325
                    if (packageFileObject.getFileObject(pkClassName, "java") == null) { // NOI18N
 
326
                        FileObject pkClass = GenerationUtils.createClass(packageFileObject, pkClassName, NbBundle.getMessage(JavaPersistenceGenerator.class, "MSG_Javadoc_PKClass", pkClassName, entityClassName));
 
327
                        generatedFOs.add(pkClass);
 
328
                    }
 
329
                }
 
330
            }
 
331
 
 
332
            // now generate the fields and methods for each entity class
 
333
            // and its primary key class
 
334
 
 
335
 
 
336
            for (int i = 0; i < entityClasses.length; i++) {
 
337
                final EntityClass entityClass = entityClasses[i];
 
338
                String entityClassName = entityClass.getClassName();
 
339
 
 
340
                if (!generatedEntityClasses.contains(entityClassName)) {
 
341
                    // this entity class already existed, we didn't create it, so we don't want to touch it
 
342
                    progressContributor.progress(entityClasses.length + i);
 
343
                    continue;
 
344
                }
 
345
                String progressMsg = NbBundle.getMessage(JavaPersistenceGenerator.class, "TXT_GeneratingClass", entityClassName);
 
346
                progressContributor.progress(progressMsg, entityClasses.length + i);
 
347
                if (progressPanel != null){
 
348
                    progressPanel.setText(progressMsg);
 
349
                }
 
350
                FileObject entityClassPackageFO = entityClass.getPackageFileObject();
 
351
                final FileObject entityClassFO = entityClassPackageFO.getFileObject(entityClassName, "java"); // NOI18N
 
352
                final FileObject pkClassFO = entityClassPackageFO.getFileObject(createPKClassName(entityClassName), "java"); // NOI18N
 
353
                try {
 
354
 
 
355
                    Set<ClassPath> bootCPs = getAllClassPaths(generationPackageFOs, ClassPath.BOOT);
 
356
                    Set<ClassPath> compileCPs = getAllClassPaths(generationPackageFOs, ClassPath.COMPILE);
 
357
                    Set<ClassPath> sourceCPs = getAllClassPaths(generationPackageFOs, ClassPath.SOURCE);
 
358
 
 
359
                    JPAClassPathHelper cpHelper = new JPAClassPathHelper(bootCPs, compileCPs, sourceCPs);
 
360
 
 
361
                    JavaSource javaSource = (pkClassFO != null) ?
 
362
                        JavaSource.create(cpHelper.createClasspathInfo(), entityClassFO, pkClassFO) :
 
363
                        JavaSource.create(cpHelper.createClasspathInfo(), entityClassFO);
 
364
                    javaSource.runModificationTask(new AbstractTask<WorkingCopy>() {
 
365
                        public void run(WorkingCopy copy) throws IOException {
 
366
                            if (copy.getFileObject().equals(entityClassFO)) {
 
367
                                new EntityClassGenerator(copy, entityClass, generateNamedQueries).run();
 
368
                            } else {
 
369
                                new PKClassGenerator(copy, entityClass).run();
 
370
                            }
 
371
                        }
 
372
                    }).commit();
 
373
                } catch (IOException e) {
 
374
                    String message = e.getMessage();
 
375
                    String newMessage = ((message == null) ?
 
376
                        NbBundle.getMessage(JavaPersistenceGenerator.class, "ERR_GeneratingClass_NoExceptionMessage", entityClassName) :
 
377
                        NbBundle.getMessage(JavaPersistenceGenerator.class, "ERR_GeneratingClass", entityClassName, message));
 
378
                    IOException wrappedException = new IOException(newMessage);
 
379
                    wrappedException.initCause(e);
 
380
                    throw wrappedException;
 
381
                }
 
382
 
 
383
            }
 
384
        }
 
385
 
 
386
 
 
387
        private static String createPKClassName(String entityClassName) {
 
388
            return entityClassName + "PK"; // NOI18N
 
389
        }
 
390
 
 
391
        private static Set<ClassPath> getAllClassPaths(Set<FileObject> fileObjects, String id) {
 
392
            Set<ClassPath> classPaths = new HashSet<ClassPath>();
 
393
            for (FileObject fileObject : fileObjects) {
 
394
                classPaths.add(ClassPath.getClassPath(fileObject, id));
 
395
            }
 
396
            return classPaths;
 
397
        }
 
398
 
 
399
 
 
400
        /**
 
401
         * Encapsulates common logic for generating classes (be it
 
402
         * entity or primary key classes). Each instance generates a single
 
403
         * class.
 
404
         */
 
405
        private abstract class ClassGenerator {
 
406
 
 
407
            protected final WorkingCopy copy;
 
408
            protected final GenerationUtils genUtils;
 
409
 
 
410
            // the entity class we are generating
 
411
            protected final EntityClass entityClass;
 
412
            // the mapping of the entity class to the database
 
413
            protected final CMPMappingModel dbMappings;
 
414
            // true if a primary key class needs to be generated along with the entity class
 
415
            protected final boolean needsPKClass;
 
416
            // the simple class name of the primary key class
 
417
            protected final String pkClassName;
 
418
            // the fully-qualified name of the primary key class
 
419
            protected final String pkFQClassName;
 
420
 
 
421
            // generated properties
 
422
            protected final List<Property> properties = new ArrayList<Property>();
 
423
            // generated methods
 
424
            protected final List<MethodTree> methods = new ArrayList<MethodTree>();
 
425
            // generated constructors
 
426
            protected final List<MethodTree> constructors = new ArrayList<MethodTree>();
 
427
            // generated fields. does not include fields of properties, just plain fields 
 
428
            protected final List<VariableTree> fields = new ArrayList<VariableTree>();
 
429
 
 
430
            // the class tree of the class we are generating
 
431
            protected ClassTree classTree;
 
432
 
 
433
            public ClassGenerator(WorkingCopy copy, EntityClass entityClass) throws IOException {
 
434
                this.copy = copy;
 
435
 
 
436
                this.entityClass = entityClass;
 
437
                dbMappings = entityClass.getCMPMapping();
 
438
                needsPKClass = !entityClass.isUsePkField();
 
439
                pkClassName = needsPKClass ? createPKClassName(entityClass.getClassName()) : null;
 
440
                pkFQClassName = entityClass.getPackage() + "." + pkClassName; // NOI18N
 
441
 
 
442
 
 
443
                genUtils = GenerationUtils.newInstance(copy);
 
444
                if (genUtils == null) {
 
445
                    throw new IllegalStateException("Cannot find a public top-level class named " + entityClass.getClassName() +  // NOI18N
 
446
                            " in " + FileUtil.getFileDisplayName(copy.getFileObject())); // NOI18N
 
447
                }
 
448
                classTree = genUtils.getClassTree();
 
449
            }
 
450
 
 
451
            protected String createFieldName(String capitalizedFieldName) {
 
452
                return createFieldNameImpl(capitalizedFieldName, false);
 
453
            }
 
454
 
 
455
            protected String createCapitalizedFieldName(String fieldName) {
 
456
                return createFieldNameImpl(fieldName, true);
 
457
            }
 
458
 
 
459
            private String createFieldNameImpl(String fieldName, boolean capitalized) {
 
460
                StringBuffer sb = new StringBuffer(fieldName);
 
461
                char firstChar = sb.charAt(0);
 
462
                sb.setCharAt(0, capitalized ? Character.toUpperCase(firstChar) : Character.toLowerCase(firstChar));
 
463
                return sb.toString();
 
464
            }
 
465
 
 
466
            /**
 
467
             * Creates a property for an entity member, that is, is creates
 
468
             * a field, a getter and a setter method.
 
469
             */
 
470
            protected Property createProperty(EntityMember m) throws IOException {
 
471
                boolean isPKMember = m.isPrimaryKey();
 
472
                List<AnnotationTree> annotations = new ArrayList<AnnotationTree>();
 
473
 
 
474
                //add @Id() only if not in an embeddable PK class
 
475
                if (isPKMember && !needsPKClass) {
 
476
                    annotations.add(genUtils.createAnnotation("javax.persistence.Id")); // NOI18N
 
477
                }
 
478
 
 
479
                boolean isLobType = m.isLobType();
 
480
                if (isLobType) {
 
481
                    annotations.add(genUtils.createAnnotation("javax.persistence.Lob")); // NOI18N
 
482
                }
 
483
 
 
484
                List<ExpressionTree> columnAnnArguments = new ArrayList();
 
485
                String memberName = m.getMemberName();
 
486
 
 
487
                String columnName = (String) dbMappings.getCMPFieldMapping().get(memberName);
 
488
                columnAnnArguments.add(genUtils.createAnnotationArgument("name", columnName)); //NOI18N
 
489
                if (!m.isNullable()) {
 
490
                    columnAnnArguments.add(genUtils.createAnnotationArgument("nullable", false)); //NOI18N
 
491
                }
 
492
                annotations.add(genUtils.createAnnotation("javax.persistence.Column", columnAnnArguments)); //NOI18N
 
493
 
 
494
                String temporalType = getMemberTemporalType(m);
 
495
                if (temporalType != null) {
 
496
                    ExpressionTree temporalAnnValueArgument = genUtils.createAnnotationArgument(null, "javax.persistence.TemporalType", temporalType); //NOI18N
 
497
                    annotations.add(genUtils.createAnnotation("javax.persistence.Temporal", Collections.singletonList(temporalAnnValueArgument)));
 
498
                }
 
499
 
 
500
                return new Property(Modifier.PRIVATE, annotations, getMemberType(m), memberName);
 
501
            }
 
502
 
 
503
            /**
 
504
             * Like {@link #createProperty}, but it only creates a variable
 
505
             * with no modififers and no annotations. Useful to pass in
 
506
             * a parameter list when creating a method or constructor.
 
507
             */
 
508
            protected VariableTree createVariable(EntityMember m) {
 
509
                return genUtils.createVariable(m.getMemberName(), getMemberType(m));
 
510
            }
 
511
 
 
512
            private String getMemberType(EntityMember m) {
 
513
                String memberType = m.getMemberType();
 
514
                if ("java.sql.Date".equals(memberType)) { //NOI18N
 
515
                    memberType = "java.util.Date";
 
516
                } else if ("java.sql.Time".equals(memberType)) { //NOI18N
 
517
                    memberType = "java.util.Date";
 
518
                } else if ("java.sql.Timestamp".equals(memberType)) { //NOI18N
 
519
                    memberType = "java.util.Date";
 
520
                }
 
521
                return memberType;
 
522
            }
 
523
 
 
524
            private String getMemberTemporalType(EntityMember m) {
 
525
                String memberType = m.getMemberType();
 
526
                String temporalType = null;
 
527
                if ("java.sql.Date".equals(memberType)) { //NOI18N
 
528
                    temporalType = "DATE";
 
529
                } else if ("java.sql.Time".equals(memberType)) { //NOI18N
 
530
                    temporalType = "TIME";
 
531
                } else if ("java.sql.Timestamp".equals(memberType)) { //NOI18N
 
532
                    temporalType = "TIMESTAMP";
 
533
                }
 
534
                return temporalType;
 
535
            }
 
536
 
 
537
            public void run() throws IOException {
 
538
                initialize();
 
539
                for (Object object : entityClass.getFields()) {
 
540
                    generateMember((EntityMember)object);
 
541
                }
 
542
                afterMembersGenerated();
 
543
                for (Object object : entityClass.getRoles()) {
 
544
                    generateRelationship((RelationshipRole)object);
 
545
                }
 
546
                finish();
 
547
 
 
548
                // add the generated members
 
549
                TreeMaker make = copy.getTreeMaker();
 
550
                int position = 0;
 
551
                for (VariableTree field : fields){
 
552
                    classTree = make.insertClassMember(classTree, position, field);
 
553
                    position++;
 
554
                }
 
555
                for (Property property : properties) {
 
556
                    classTree = make.insertClassMember(classTree, position, property.getField());
 
557
                    position++;
 
558
                }
 
559
                for (MethodTree constructor : constructors) {
 
560
                    classTree = make.addClassMember(classTree, constructor);
 
561
                }
 
562
                for (Property property : properties) {
 
563
                    classTree = make.addClassMember(classTree, property.getGetter());
 
564
                    classTree = make.addClassMember(classTree, property.getSetter());
 
565
                }
 
566
                for (MethodTree method : methods) {
 
567
                    classTree = make.addClassMember(classTree, method);
 
568
                }
 
569
                copy.rewrite(genUtils.getClassTree(), classTree);
 
570
            }
 
571
 
 
572
            /**
 
573
             * Called at the beginning of the generation process.
 
574
             */
 
575
            protected abstract void initialize() throws IOException;
 
576
 
 
577
            /**
 
578
             * Called for each entity class member.
 
579
             */
 
580
            protected abstract void generateMember(EntityMember m) throws IOException;
 
581
 
 
582
            /**
 
583
             * Called after all members have been generated.
 
584
             */
 
585
            protected abstract void afterMembersGenerated() throws IOException;
 
586
 
 
587
            /**
 
588
             * Called for each relationship.
 
589
             */
 
590
            protected abstract void generateRelationship(RelationshipRole role) throws IOException;
 
591
 
 
592
            /**
 
593
             * Called at the end of the generation process.
 
594
             */
 
595
            protected abstract void finish() throws IOException;
 
596
 
 
597
            /**
 
598
             * Encapsulates a generated property, that is, its field, getter
 
599
             * and setter method.
 
600
             */
 
601
            protected final class Property {
 
602
 
 
603
                private final VariableTree field;
 
604
                private final MethodTree getter;
 
605
                private final MethodTree setter;
 
606
 
 
607
                public Property(Modifier modifier, List<AnnotationTree> annotations, String type, String name) throws IOException {
 
608
                    this(modifier, annotations, genUtils.createType(type), name);
 
609
                }
 
610
 
 
611
                public Property(Modifier modifier, List<AnnotationTree> annotations, TypeMirror type, String name) throws IOException {
 
612
                    this(modifier, annotations, copy.getTreeMaker().Type(type), name);
 
613
                }
 
614
 
 
615
                private Property(Modifier modifier, List<AnnotationTree> annotations, Tree typeTree, String name) throws IOException {
 
616
                    TreeMaker make = copy.getTreeMaker();
 
617
                    field = make.Variable(
 
618
                            make.Modifiers(EnumSet.of(modifier), fieldAccess ? annotations : Collections.<AnnotationTree>emptyList()),
 
619
                            name,
 
620
                            typeTree,
 
621
                            null);
 
622
                    getter = genUtils.createPropertyGetterMethod(
 
623
                            make.Modifiers(EnumSet.of(Modifier.PUBLIC), fieldAccess ? Collections.<AnnotationTree>emptyList() : annotations),
 
624
                            name,
 
625
                            typeTree);
 
626
                    setter = genUtils.createPropertySetterMethod(
 
627
                            genUtils.createModifiers(Modifier.PUBLIC),
 
628
                            name,
 
629
                            typeTree);
 
630
                }
 
631
 
 
632
                public VariableTree getField() {
 
633
                    return field;
 
634
                }
 
635
 
 
636
                public MethodTree getGetter() {
 
637
                    return getter;
 
638
                }
 
639
 
 
640
                public MethodTree getSetter() {
 
641
                    return setter;
 
642
                }
 
643
            }
 
644
        }
 
645
 
 
646
        /**
 
647
         * An implementation of ClassGenerator which generates entity classes.
 
648
         */
 
649
        private final class EntityClassGenerator extends ClassGenerator {
 
650
 
 
651
            // the simple name of the entity class
 
652
            private final String entityClassName;
 
653
            // the fully-qualified name of the entity class
 
654
            private final String entityFQClassName;
 
655
            // the non-nullable properties (not including the primary key ones)
 
656
            private final List<Property> nonNullableProps = new ArrayList<Property>();
 
657
            // the names of the primary key columns
 
658
            private final List<String> pkColumnNames = new ArrayList<String>();
 
659
            // variables correspoding to the fields in the primary key classs (or empty if no primary key class)
 
660
            private final List<VariableTree> pkClassVariables = new ArrayList<VariableTree>();
 
661
            // the list of @NamedQuery annotations which will be added to the entity class
 
662
            private final List<ExpressionTree> namedQueryAnnotations = new ArrayList<ExpressionTree>();
 
663
            /**
 
664
             * Specifies whether named queries should be generated.
 
665
             */
 
666
            private final boolean generateNamedQueries;
 
667
 
 
668
            // the property for the primary key (or the primary key class)
 
669
            private Property pkProperty;
 
670
            // the prefix or all named queries ("select ... ")
 
671
            private String namedQueryPrefix;
 
672
 
 
673
 
 
674
 
 
675
            public EntityClassGenerator(WorkingCopy copy, EntityClass entityClass, boolean generateNamedQueries) throws IOException {
 
676
                super(copy, entityClass);
 
677
                this.generateNamedQueries = generateNamedQueries;
 
678
                entityClassName = entityClass.getClassName();
 
679
                assert genUtils.getTypeElement().getSimpleName().contentEquals(entityClassName);
 
680
                entityFQClassName = entityClass.getPackage() + "." + entityClassName;
 
681
            }
 
682
 
 
683
            protected void initialize() throws IOException {
 
684
                classTree = genUtils.ensureNoArgConstructor(classTree);
 
685
                if (genSerializableEntities) {
 
686
                    classTree = genUtils.addImplementsClause(classTree, "java.io.Serializable"); // NOI18N
 
687
                }
 
688
                classTree = genUtils.addAnnotation(classTree, genUtils.createAnnotation("javax.persistence.Entity")); // NOI18N
 
689
                ExpressionTree tableNameArgument = genUtils.createAnnotationArgument("name", dbMappings.getTableName()); // NOI18N
 
690
                classTree = genUtils.addAnnotation(classTree, genUtils.createAnnotation("javax.persistence.Table", Collections.singletonList(tableNameArgument)));
 
691
 
 
692
                if (needsPKClass) {
 
693
                    String pkFieldName = createFieldName(pkClassName);
 
694
                    pkProperty = new Property(
 
695
                            Modifier.PROTECTED,
 
696
                            Collections.singletonList(genUtils.createAnnotation("javax.persistence.EmbeddedId")),
 
697
                            pkFQClassName,
 
698
                            pkFieldName);
 
699
                    properties.add(pkProperty);
 
700
                }
 
701
 
 
702
                //TODO: javadoc - generate or fake in test mode
 
703
                //        b.setCommentDataAuthor(authorOverride);
 
704
                //        b.setCommentDataDate(dateOverride);
 
705
            }
 
706
 
 
707
            protected void generateMember(EntityMember m) throws IOException {
 
708
                String memberName = m.getMemberName();
 
709
                boolean isPKMember = m.isPrimaryKey();
 
710
                Property property = null;
 
711
                if (isPKMember) {
 
712
                    if (needsPKClass) {
 
713
                        pkClassVariables.add(createVariable(m));
 
714
                    } else {
 
715
                        pkProperty = property = createProperty(m);
 
716
                    }
 
717
                    String pkColumnName = (String)dbMappings.getCMPFieldMapping().get(memberName);
 
718
                    pkColumnNames.add(pkColumnName);
 
719
                } else {
 
720
                    property = createProperty(m);
 
721
                    if (!m.isNullable()) {
 
722
                        nonNullableProps.add(property);
 
723
                    }
 
724
                }
 
725
                // we don't create the property only if the current member is
 
726
                // part of a primary key, in which case it will be put in the primary key class
 
727
                assert (property != null) || (property == null && isPKMember && needsPKClass);
 
728
                if (property != null) {
 
729
                    properties.add(property);
 
730
                }
 
731
 
 
732
                // generate equivalent of finder methods - named query annotations
 
733
                if (generateNamedQueries && !m.isLobType()) {
 
734
                    List<ExpressionTree> namedQueryAnnArguments = new ArrayList<ExpressionTree>();
 
735
                    namedQueryAnnArguments.add(genUtils.createAnnotationArgument("name", entityClassName + ".findBy" + createCapitalizedFieldName(memberName))); //NOI18N
 
736
 
 
737
                    if (namedQueryPrefix == null) {
 
738
                        char firstLetter = entityClassName.toLowerCase().charAt(0);
 
739
                        namedQueryPrefix = "SELECT " + firstLetter + " FROM " + entityClassName + " " + firstLetter + " WHERE " + firstLetter + "."; // NOI18N
 
740
                    }
 
741
                    // need a prefix of "pk_field_name." if this is part of a composite pk
 
742
                    String memberAccessString = ((needsPKClass && isPKMember) ? (pkProperty.getField().getName().toString() + "." + memberName) : memberName); // NOI18N
 
743
                    namedQueryAnnArguments.add(genUtils.createAnnotationArgument(
 
744
                            "query", namedQueryPrefix + //NOI18N
 
745
                            memberAccessString + ((genNamedParams) ? (" = :" + memberName) : "= ?1"))); //NOI18N
 
746
                    namedQueryAnnotations.add(genUtils.createAnnotation("javax.persistence.NamedQuery", namedQueryAnnArguments)); //NOI18N
 
747
                }
 
748
            }
 
749
 
 
750
            protected void afterMembersGenerated() {
 
751
                classTree = genUtils.addAnnotation(classTree, genUtils.createAnnotation("javax.persistence.NamedQueries", // NOI18N
 
752
                        Collections.singletonList(genUtils.createAnnotationArgument(null, namedQueryAnnotations))));
 
753
            }
 
754
 
 
755
            protected void generateRelationship(RelationshipRole role) throws IOException {
 
756
                String memberName = role.getFieldName();
 
757
 
 
758
                // XXX getRelationshipFieldType() does not work well when entity classes
 
759
                // are not all generated to the same package
 
760
                String typeName = getRelationshipFieldType(role, entityClass.getPackage());
 
761
                TypeMirror fieldType = copy.getElements().getTypeElement(typeName).asType();
 
762
                if (role.isToMany()) {
 
763
                    // XXX this will probably not resolve imports
 
764
                    TypeElement collectionType = copy.getElements().getTypeElement("java.util.Collection"); // NOI18N
 
765
                    fieldType = copy.getTypes().getDeclaredType(collectionType, fieldType);
 
766
                }
 
767
 
 
768
                List<AnnotationTree> annotations = new ArrayList<AnnotationTree>();
 
769
                List<ExpressionTree> annArguments = new ArrayList<ExpressionTree>();
 
770
                if (role.isCascade()) {
 
771
                    annArguments.add(genUtils.createAnnotationArgument("cascade", "javax.persistence.CascadeType", "ALL")); // NOI18N
 
772
                }
 
773
                if (role.equals(role.getParent().getRoleB())) {
 
774
                    annArguments.add(genUtils.createAnnotationArgument("mappedBy", role.getParent().getRoleA().getFieldName())); // NOI18N
 
775
                } else {
 
776
                    if (role.isMany() && role.isToMany()) {
 
777
                        List<ExpressionTree> joinTableAnnArguments = new ArrayList<ExpressionTree>();
 
778
                        joinTableAnnArguments.add(genUtils.createAnnotationArgument("name", (String) dbMappings.getJoinTableMapping().get(role.getFieldName()))); //NOI18N
 
779
 
 
780
                        CMPMappingModel.JoinTableColumnMapping joinColumnMap = dbMappings.getJoinTableColumnMppings().get(role.getFieldName());
 
781
 
 
782
                        List<AnnotationTree> joinCols = new ArrayList<AnnotationTree>();
 
783
                        String[] colNames = joinColumnMap.getColumns();
 
784
                        String[] refColNames = joinColumnMap.getReferencedColumns();
 
785
                        for(int colIndex = 0; colIndex < colNames.length; colIndex++) {
 
786
                            List<ExpressionTree> attrs = new ArrayList<ExpressionTree>();
 
787
                            attrs.add(genUtils.createAnnotationArgument("name", colNames[colIndex])); //NOI18N
 
788
                            attrs.add(genUtils.createAnnotationArgument("referencedColumnName", refColNames[colIndex])); //NOI18N
 
789
                            joinCols.add(genUtils.createAnnotation("javax.persistence.JoinColumn", attrs)); //NOI18N
 
790
                        }
 
791
                        joinTableAnnArguments.add(genUtils.createAnnotationArgument("joinColumns", joinCols)); // NOI18N
 
792
 
 
793
                        List<AnnotationTree> inverseCols = new ArrayList<AnnotationTree>();
 
794
                        String[] invColNames = joinColumnMap.getInverseColumns();
 
795
                        String[] refInvColNames = joinColumnMap.getReferencedInverseColumns();
 
796
                        for(int colIndex = 0; colIndex < invColNames.length; colIndex++) {
 
797
                            List<ExpressionTree> attrs = new ArrayList<ExpressionTree>();
 
798
                            attrs.add(genUtils.createAnnotationArgument("name", invColNames[colIndex])); //NOI18N
 
799
                            attrs.add(genUtils.createAnnotationArgument("referencedColumnName", refInvColNames[colIndex])); //NOI18N
 
800
                            inverseCols.add(genUtils.createAnnotation("javax.persistence.JoinColumn", attrs)); // NOI18N
 
801
                        }
 
802
                        joinTableAnnArguments.add(genUtils.createAnnotationArgument("inverseJoinColumns", inverseCols)); // NOI18N
 
803
 
 
804
                        annotations.add(genUtils.createAnnotation("javax.persistence.JoinTable", joinTableAnnArguments)); // NOI18N
 
805
                    } else {
 
806
                        String[] colNames = (String[]) dbMappings.getCmrFieldMapping().get(role.getFieldName());
 
807
                        CMPMappingModel relatedMappings = beanMap.get(role.getParent().getRoleB().getEntityName()).getCMPMapping();
 
808
                        String[] invColNames = (String[]) relatedMappings.getCmrFieldMapping().get(role.getParent().getRoleB().getFieldName());
 
809
                        if (colNames.length == 1) {
 
810
                            List<ExpressionTree> attrs = new ArrayList<ExpressionTree>();
 
811
                            attrs.add(genUtils.createAnnotationArgument("name", colNames[0])); //NOI18N
 
812
                            attrs.add(genUtils.createAnnotationArgument("referencedColumnName", invColNames[0])); //NOI18N
 
813
                            makeReadOnlyIfNecessary(pkColumnNames, colNames[0], attrs);
 
814
                            annotations.add(genUtils.createAnnotation("javax.persistence.JoinColumn", attrs)); //NOI18N
 
815
                        } else {
 
816
                            List<AnnotationTree> joinCols = new ArrayList<AnnotationTree>();
 
817
                            for(int colIndex = 0; colIndex < colNames.length; colIndex++) {
 
818
                                List<ExpressionTree> attrs = new ArrayList<ExpressionTree>();
 
819
                                attrs.add(genUtils.createAnnotationArgument("name", colNames[colIndex])); //NOI18N
 
820
                                attrs.add(genUtils.createAnnotationArgument("referencedColumnName", invColNames[colIndex])); //NOI18N
 
821
                                makeReadOnlyIfNecessary(pkColumnNames, colNames[colIndex], attrs);
 
822
                                joinCols.add(genUtils.createAnnotation("javax.persistence.JoinColumn", attrs)); // NOI18N
 
823
                            }
 
824
                            ExpressionTree joinColumnsNameAttrValue = genUtils.createAnnotationArgument(null, joinCols);
 
825
                            AnnotationTree joinColumnsAnnotation = genUtils.createAnnotation("javax.persistence.JoinColumns", Collections.singletonList(joinColumnsNameAttrValue)); //NOI18N
 
826
                            annotations.add(joinColumnsAnnotation);
 
827
                        }
 
828
                    }
 
829
                }
 
830
                String relationAnn;
 
831
                if (role.isMany() && role.isToMany()) {
 
832
                    relationAnn = "ManyToMany"; //NOI18N
 
833
                } else if (role.isMany()) {
 
834
                    relationAnn = "ManyToOne"; //NOI18N
 
835
                } else if (role.isToMany()) {
 
836
                    relationAnn = "OneToMany"; //NOI18N
 
837
                } else {
 
838
                    relationAnn = "OneToOne";  //NOI18N
 
839
                }
 
840
                annotations.add(genUtils.createAnnotation("javax.persistence." + relationAnn, annArguments)); // NOI18N
 
841
 
 
842
                properties.add(new Property(Modifier.PRIVATE, annotations, fieldType, memberName));
 
843
            }
 
844
 
 
845
            /**
 
846
             * Creates the <code>serialVersionUID</code> field with
 
847
             * the initial value of <code>1L</code>.
 
848
             * 
 
849
             * @return the created field.
 
850
             */ 
 
851
            private VariableTree createSerialVersionUID(){
 
852
                Set<Modifier> serialVersionUIDModifiers = new HashSet<Modifier>();
 
853
                serialVersionUIDModifiers.add(Modifier.PRIVATE);
 
854
                serialVersionUIDModifiers.add(Modifier.STATIC);
 
855
                serialVersionUIDModifiers.add(Modifier.FINAL);
 
856
 
 
857
                TreeMaker make = copy.getTreeMaker();
 
858
                VariableTree serialVersionUID = make.Variable(make.Modifiers(serialVersionUIDModifiers), 
 
859
                        "serialVersionUID", genUtils.createType("long"), make.Literal(Long.valueOf("1"))); //NO18N
 
860
                
 
861
                return serialVersionUID;
 
862
            }
 
863
            
 
864
            protected void finish() {
 
865
                // create a constructor which takes the primary key field as argument
 
866
                VariableTree pkFieldParam = genUtils.removeModifiers(pkProperty.getField());
 
867
                List<VariableTree> pkFieldParams = Collections.singletonList(pkFieldParam);
 
868
                constructors.add(genUtils.createAssignmentConstructor(genUtils.createModifiers(Modifier.PUBLIC), entityClassName, pkFieldParams));
 
869
 
 
870
                // if different than pk fields constructor, add constructor
 
871
                // which takes all non-nullable non-relationship fields as args
 
872
                if (nonNullableProps.size() > 0) {
 
873
                    List<VariableTree> nonNullableParams = new ArrayList<VariableTree>(nonNullableProps.size() + 1);
 
874
                    nonNullableParams.add(pkFieldParam);
 
875
                    for (Property property : nonNullableProps) {
 
876
                        nonNullableParams.add(genUtils.removeModifiers(property.getField()));
 
877
                    }
 
878
                    constructors.add(genUtils.createAssignmentConstructor(genUtils.createModifiers(Modifier.PUBLIC), entityClassName, nonNullableParams));
 
879
                }
 
880
 
 
881
                // create a constructor which takes the fields of the primary key class as arguments
 
882
                if (pkClassVariables.size() > 0) {
 
883
                    StringBuilder body = new StringBuilder(30 + 30 * pkClassVariables.size());
 
884
                    body.append("{"); // NOI18N
 
885
                    body.append("this." + pkProperty.getField().getName() + " = new " + pkClassName + "("); // NOI18N
 
886
                    for (Iterator<VariableTree> i = pkClassVariables.iterator(); i.hasNext();) {
 
887
                        body.append(i.next().getName());
 
888
                        body.append(i.hasNext() ? ", " : ");"); // NOI18N
 
889
                    }
 
890
                    body.append("}"); // NOI18N
 
891
                    TreeMaker make = copy.getTreeMaker();
 
892
                    constructors.add(make.Constructor(
 
893
                            make.Modifiers(EnumSet.of(Modifier.PUBLIC), Collections.<AnnotationTree>emptyList()),
 
894
                            Collections.<TypeParameterTree>emptyList(),
 
895
                            pkClassVariables,
 
896
                            Collections.<ExpressionTree>emptyList(),
 
897
                            body.toString()));
 
898
                }
 
899
 
 
900
                // add equals and hashCode methods
 
901
                EntityMethodGenerator methodGenerator = new EntityMethodGenerator(copy, genUtils);
 
902
                methods.add(methodGenerator.createHashCodeMethod(pkFieldParams));
 
903
                methods.add(methodGenerator.createEqualsMethod(entityClassName, pkFieldParams));
 
904
                methods.add(methodGenerator.createToStringMethod(entityFQClassName, pkFieldParams));
 
905
                
 
906
                // add the serialVersionUID field
 
907
                fields.add(createSerialVersionUID());
 
908
            }
 
909
 
 
910
            private String getRelationshipFieldType(RelationshipRole role, String pkg) {
 
911
                RelationshipRole rA = role.getParent().getRoleA();
 
912
                RelationshipRole rB = role.getParent().getRoleB();
 
913
                RelationshipRole otherRole = role.equals(rA) ? rB : rA;                
 
914
                return pkg.length() == 0 ? otherRole.getEntityName() : pkg + "." + otherRole.getEntityName(); // NOI18N
 
915
            }
 
916
 
 
917
            private void makeReadOnlyIfNecessary(List<String> pkColumnNames, String testColumnName, List<ExpressionTree> attrs) {
 
918
                // if the join column is a pk column, add insertable = false, updatable = false
 
919
                if (pkColumnNames.contains(testColumnName)) {
 
920
                    attrs.add(genUtils.createAnnotationArgument("insertable", false)); //NOI18N
 
921
                    attrs.add(genUtils.createAnnotationArgument("updatable", false)); //NOI18N
 
922
                }
 
923
            }
 
924
        }
 
925
 
 
926
        /**
 
927
         * An implementation of ClassGenerator which generates primary key
 
928
         * classes.
 
929
         */
 
930
        private final class PKClassGenerator extends ClassGenerator {
 
931
 
 
932
            public PKClassGenerator(WorkingCopy copy, EntityClass entityClass) throws IOException {
 
933
                super(copy, entityClass);
 
934
            }
 
935
 
 
936
            protected void initialize() throws IOException {
 
937
                classTree = genUtils.ensureNoArgConstructor(classTree);
 
938
                // primary key class must be serializable and @Embeddable
 
939
                classTree = genUtils.addImplementsClause(classTree, "java.io.Serializable"); //NOI18N
 
940
                classTree = genUtils.addAnnotation(classTree, genUtils.createAnnotation("javax.persistence.Embeddable")); // NOI18N
 
941
            }
 
942
 
 
943
            protected void generateMember(EntityMember m) throws IOException {
 
944
                if (!m.isPrimaryKey()) {
 
945
                    return;
 
946
                }
 
947
                Property property = createProperty(m);
 
948
                properties.add(property);
 
949
            }
 
950
 
 
951
            protected void afterMembersGenerated() {
 
952
            }
 
953
 
 
954
            protected void generateRelationship(RelationshipRole relationship) {
 
955
            }
 
956
 
 
957
            protected void finish() {
 
958
                // add a constructor which takes the fields of the primary key class as arguments
 
959
                List<VariableTree> parameters = new ArrayList<VariableTree>(properties.size());
 
960
                for (Property property : properties) {
 
961
                    parameters.add(genUtils.removeModifiers(property.getField()));
 
962
                }
 
963
                constructors.add(genUtils.createAssignmentConstructor(genUtils.createModifiers(Modifier.PUBLIC), pkClassName, parameters));
 
964
 
 
965
                // add equals and hashCode methods
 
966
                EntityMethodGenerator methodGenerator = new EntityMethodGenerator(copy, genUtils);
 
967
                methods.add(methodGenerator.createHashCodeMethod(parameters));
 
968
                methods.add(methodGenerator.createEqualsMethod(pkClassName, parameters));
 
969
                methods.add(methodGenerator.createToStringMethod(pkFQClassName, parameters));
 
970
            }
 
971
        }
 
972
    }
 
973
}