001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.openjpa.persistence.jdbc;
020:
021: import org.apache.openjpa.persistence.AnnotationPersistenceMetaDataSerializer;
022: import org.apache.openjpa.persistence.PersistenceStrategy;
023: import org.apache.openjpa.persistence.AnnotationBuilder;
024: import org.apache.openjpa.jdbc.meta.QueryResultMapping;
025: import org.apache.openjpa.jdbc.meta.MappingRepository;
026: import org.apache.openjpa.jdbc.meta.ClassMapping;
027: import org.apache.openjpa.jdbc.meta.FieldMapping;
028: import org.apache.openjpa.jdbc.meta.ClassMappingInfo;
029: import org.apache.openjpa.jdbc.meta.DiscriminatorMappingInfo;
030: import org.apache.openjpa.jdbc.meta.MappingInfo;
031: import org.apache.openjpa.jdbc.meta.SequenceMapping;
032: import org.apache.openjpa.jdbc.meta.ValueMappingInfo;
033: import org.apache.openjpa.jdbc.meta.strats.FlatClassStrategy;
034: import org.apache.openjpa.jdbc.meta.strats.VerticalClassStrategy;
035: import org.apache.openjpa.jdbc.meta.strats.FullClassStrategy;
036: import org.apache.openjpa.jdbc.meta.strats.EnumValueHandler;
037: import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
038: import org.apache.openjpa.jdbc.schema.*;
039: import org.apache.openjpa.jdbc.schema.Unique;
040: import org.apache.openjpa.jdbc.sql.DBDictionary;
041: import org.apache.openjpa.meta.MetaDataRepository;
042: import org.apache.openjpa.meta.ClassMetaData;
043: import org.apache.openjpa.meta.FieldMetaData;
044: import org.apache.openjpa.meta.JavaTypes;
045: import org.apache.openjpa.meta.SequenceMetaData;
046: import org.apache.openjpa.meta.MetaDataModes;
047: import org.apache.commons.lang.StringUtils;
048:
049: import java.util.List;
050: import java.util.ArrayList;
051: import java.util.Collection;
052: import java.util.Collections;
053: import java.util.Map;
054: import java.util.HashMap;
055: import java.sql.Types;
056: import java.lang.annotation.Annotation;
057:
058: import serp.util.Strings;
059:
060: import javax.persistence.TemporalType;
061: import javax.persistence.EnumType;
062: import javax.persistence.InheritanceType;
063: import javax.persistence.Table;
064: import javax.persistence.SecondaryTable;
065: import javax.persistence.Inheritance;
066: import javax.persistence.DiscriminatorValue;
067: import javax.persistence.DiscriminatorColumn;
068: import javax.persistence.JoinTable;
069: import javax.persistence.Lob;
070: import javax.persistence.Temporal;
071: import javax.persistence.Enumerated;
072: import javax.persistence.UniqueConstraint;
073: import javax.persistence.TableGenerator;
074: import javax.persistence.JoinColumns;
075: import javax.persistence.JoinColumn;
076: import javax.persistence.PrimaryKeyJoinColumn;
077: import javax.persistence.PrimaryKeyJoinColumns;
078: import javax.persistence.SqlResultSetMapping;
079: import javax.persistence.EntityResult;
080: import javax.persistence.FieldResult;
081: import javax.persistence.ColumnResult;
082:
083: //@todo: javadocs
084:
085: /**
086: * Serializes persistence mappings as annotations.
087: *
088: * @since 1.0.0
089: * @author Steve Kim
090: * @author Gokhan Ergul
091: * @nojavadoc
092: */
093: public class AnnotationPersistenceMappingSerializer extends
094: AnnotationPersistenceMetaDataSerializer {
095:
096: private static final int TYPE_RESULTMAP = TYPE_QUERY + 1;
097:
098: private List<QueryResultMapping> _results = null;
099: private boolean _sync = false;
100:
101: private Map<QueryResultMapping, List<AnnotationBuilder>> _rsmAnnos = null;
102:
103: /**
104: * Constructor. Supply configuration.
105: */
106: public AnnotationPersistenceMappingSerializer(JDBCConfiguration conf) {
107: super (conf);
108: }
109:
110: /**
111: * Whether to automatically synchronize mapping info with data available
112: * from mapped components before serialization. Defaults to false.
113: */
114: public boolean getSyncMappingInfo() {
115: return _sync;
116: }
117:
118: /**
119: * Whether to automatically synchronize mapping info with data available
120: * from mapped components before serialization. Defaults to false.
121: */
122: public void setSyncMappingInfo(boolean sync) {
123: _sync = sync;
124: }
125:
126: /**
127: * Adds the given result set mapping to local cache.
128: */
129: public void addQueryResultMapping(QueryResultMapping meta) {
130: if (_results == null)
131: _results = new ArrayList<QueryResultMapping>();
132: _results.add(meta);
133: }
134:
135: /**
136: * Removes given result set mapping from the local cache.
137: */
138: public boolean removeQueryResultMapping(QueryResultMapping meta) {
139: return _results != null && _results.remove(meta);
140: }
141:
142: @Override
143: public void addAll(MetaDataRepository repos) {
144: super .addAll(repos);
145: for (QueryResultMapping res : ((MappingRepository) repos)
146: .getQueryResultMappings())
147: addQueryResultMapping(res);
148: }
149:
150: @Override
151: public boolean removeAll(MetaDataRepository repos) {
152: boolean removed = super .removeAll(repos);
153: for (QueryResultMapping res : ((MappingRepository) repos)
154: .getQueryResultMappings())
155: removed |= removeQueryResultMapping(res);
156: return removed;
157: }
158:
159: @Override
160: public void clear() {
161: super .clear();
162: if (_results != null)
163: _results.clear();
164: }
165:
166: /**
167: * Add an annotation builder to list of builders for the specified
168: * class metadata.
169: */
170: protected void addAnnotation(AnnotationBuilder ab,
171: QueryResultMapping meta) {
172: if (_rsmAnnos == null)
173: _rsmAnnos = new HashMap<QueryResultMapping, List<AnnotationBuilder>>();
174: List<AnnotationBuilder> list = _rsmAnnos.get(meta);
175: if (list == null) {
176: list = new ArrayList<AnnotationBuilder>();
177: _rsmAnnos.put(meta, list);
178: }
179: list.add(ab);
180: }
181:
182: /**
183: * Creates an an annotation builder for the specified class metadata
184: * and adds it to list of builders.
185: */
186: protected AnnotationBuilder addAnnotation(
187: Class<? extends Annotation> annType, QueryResultMapping meta) {
188: AnnotationBuilder ab = newAnnotationBuilder(annType);
189: if (meta == null)
190: return ab;
191: addAnnotation(ab, meta);
192: return ab;
193: }
194:
195: @Override
196: protected void serializeClass(ClassMetaData meta) {
197: if (_sync && isMappingMode() && meta instanceof ClassMapping) {
198: // sync if resolved and mapped
199: ClassMapping cls = (ClassMapping) meta;
200: if ((cls.getResolve() & MetaDataModes.MODE_MAPPING) != 0
201: && cls.isMapped()) {
202: cls.syncMappingInfo();
203: cls.getDiscriminator().syncMappingInfo();
204: cls.getVersion().syncMappingInfo();
205: FieldMapping[] fields;
206: if (cls.getEmbeddingMetaData() == null)
207: fields = cls.getDefinedFieldMappings();
208: else
209: fields = cls.getFieldMappings();
210: for (FieldMapping f : fields)
211: f.syncMappingInfo();
212: }
213: }
214: super .serializeClass(meta);
215: }
216:
217: @Override
218: protected void serializeClassMappingContent(ClassMetaData mapping) {
219: ClassMapping cls = (ClassMapping) mapping;
220: ClassMappingInfo info = cls.getMappingInfo();
221: AnnotationBuilder abTable = addAnnotation(Table.class, mapping);
222: serializeTable(info.getTableName(), Strings
223: .getClassName(mapping.getDescribedType()), null, info
224: .getUniques(), abTable);
225: serializeColumns(info, ColType.PK_JOIN, null, abTable, cls);
226: for (String second : info.getSecondaryTableNames()) {
227: AnnotationBuilder abSecTable = addAnnotation(
228: SecondaryTable.class, mapping);
229: serializeTable(second, null, info, null, abSecTable);
230: }
231: }
232:
233: @Override
234: protected void serializeInheritanceContent(ClassMetaData mapping) {
235: ClassMapping cls = (ClassMapping) mapping;
236: ClassMappingInfo info = cls.getMappingInfo();
237: DiscriminatorMappingInfo dinfo = cls.getDiscriminator()
238: .getMappingInfo();
239: String strat = info.getHierarchyStrategy();
240: if (null == strat)
241: return;
242: String itypecls = Strings.getClassName(InheritanceType.class);
243: AnnotationBuilder abInheritance = addAnnotation(
244: Inheritance.class, mapping);
245: if (FlatClassStrategy.ALIAS.equals(strat))
246: abInheritance.add("strategy", itypecls + ".SINGLE_TABLE");
247: else if (VerticalClassStrategy.ALIAS.equals(strat))
248: abInheritance.add("strategy", itypecls + ".JOINED");
249: else if (FullClassStrategy.ALIAS.equals(strat))
250: abInheritance
251: .add("strategy", itypecls + ".TABLE_PER_CLASS");
252: if (dinfo.getValue() != null) {
253: AnnotationBuilder abDiscVal = addAnnotation(
254: DiscriminatorValue.class, mapping);
255: abDiscVal.add(null, dinfo.getValue());
256: }
257: AnnotationBuilder abDiscCol = addAnnotation(
258: DiscriminatorColumn.class, mapping);
259: serializeColumns(dinfo, ColType.DISC, null, abDiscCol, null);
260: }
261:
262: /**
263: * Serialize table optionally listing primary-key-joins stored
264: * in the given {@link org.apache.openjpa.jdbc.meta.ClassMappingInfo}.
265: */
266: private void serializeTable(String table, String defaultName,
267: ClassMappingInfo secondaryInfo, Unique[] uniques,
268: AnnotationBuilder ab) {
269: List<Column> cols = null;
270: if (secondaryInfo != null)
271: cols = (List<Column>) secondaryInfo
272: .getSecondaryTableJoinColumns(table);
273:
274: boolean print = (cols != null && cols.size() > 0)
275: || (uniques != null && uniques.length > 0);
276: if (table != null
277: && (defaultName == null || !defaultName.equals(table))) {
278: print = true;
279: int index = table.indexOf('.');
280: if (index < 0)
281: ab.add("name", table);
282: else {
283: ab.add("schema", table.substring(0, index));
284: ab.add("name", table.substring(index + 1));
285: }
286: }
287: if (print) {
288: if (cols != null) {
289: for (Column col : cols)
290: serializeColumn(col, ColType.PK_JOIN, null, false,
291: ab, null);
292: }
293: if (uniques != null) {
294: for (Unique unique : uniques) {
295: AnnotationBuilder abUniqueConst = newAnnotationBuilder(UniqueConstraint.class);
296: serializeUniqueConstraint(unique, abUniqueConst);
297: ab.add("uniqueConstraints", abUniqueConst);
298: }
299: }
300: }
301: }
302:
303: @Override
304: protected boolean serializeAttributeOverride(FieldMetaData fmd,
305: FieldMetaData orig) {
306: if (orig == null || fmd == orig)
307: return false;
308:
309: FieldMapping field = (FieldMapping) fmd;
310: FieldMapping field2 = (FieldMapping) orig;
311: if (field.getMappingInfo().hasSchemaComponents()
312: || field2.getMappingInfo().hasSchemaComponents())
313: return true;
314:
315: ValueMappingInfo info = field.getValueInfo();
316: List<Column> cols = (List<Column>) info.getColumns();
317: if (cols == null || cols.size() == 0)
318: return false;
319: ValueMappingInfo info2 = field2.getValueInfo();
320: List<Column> cols2 = (List<Column>) info2.getColumns();
321: if (cols2 == null || cols2.size() != cols.size())
322: return true;
323: if (cols.size() != 1)
324: return true;
325:
326: Column col;
327: Column col2;
328: for (int i = 0; i < cols.size(); i++) {
329: col = cols.get(i);
330: col2 = cols2.get(i);
331: if (!StringUtils.equals(col.getName(), col2.getName()))
332: return true;
333: if (!StringUtils.equals(col.getTypeName(), col2
334: .getTypeName()))
335: return true;
336: if (col.getSize() != col2.getSize())
337: return true;
338: if (col.getDecimalDigits() != col2.getDecimalDigits())
339: return true;
340: if (col.getFlag(Column.FLAG_UNINSERTABLE) != col2
341: .getFlag(Column.FLAG_UNINSERTABLE))
342: return true;
343: if (col.getFlag(Column.FLAG_UNUPDATABLE) != col2
344: .getFlag(Column.FLAG_UNUPDATABLE))
345: return true;
346: }
347: return false;
348: }
349:
350: @Override
351: protected void serializeAttributeOverrideMappingContent(
352: FieldMetaData fmd, FieldMetaData orig, AnnotationBuilder ab) {
353: FieldMapping fm = (FieldMapping) fmd;
354: serializeColumns(fm.getValueInfo(), ColType.COL, fm
355: .getMappingInfo().getTableName(), ab, fmd);
356: }
357:
358: @Override
359: protected PersistenceStrategy getStrategy(FieldMetaData fmd) {
360: PersistenceStrategy strat = super .getStrategy(fmd);
361: FieldMapping field = (FieldMapping) fmd;
362: switch (strat) {
363: case MANY_MANY:
364: // we can differentiate a one-many by the fact that there is no
365: // secondary table join, or the fk is unique
366: if (field.getMappedBy() == null
367: && (field.getMappingInfo().getJoinDirection() == MappingInfo.JOIN_NONE || field
368: .getElementMapping().getValueInfo()
369: .getUnique() != null))
370: return PersistenceStrategy.ONE_MANY;
371: break;
372: case MANY_ONE:
373: // inverse join cols or unique fk?
374: if (field.getValueInfo().getJoinDirection() == MappingInfo.JOIN_INVERSE
375: || field.getValueInfo().getUnique() != null)
376: return PersistenceStrategy.ONE_ONE;
377:
378: // scan for primary-key-join-column
379: List<Column> cols = field.getValueInfo().getColumns();
380: boolean pkJoin = cols != null && cols.size() > 0;
381: for (int i = 0; pkJoin && i < cols.size(); i++)
382: pkJoin = cols.get(i).getFlag(Column.FLAG_PK_JOIN);
383: if (pkJoin)
384: return PersistenceStrategy.ONE_ONE;
385: break;
386: }
387: return strat;
388: }
389:
390: @Override
391: protected void serializeFieldMappingContent(FieldMetaData fmd,
392: PersistenceStrategy strategy, AnnotationBuilder ab) {
393: if (fmd.getMappedBy() != null)
394: return;
395:
396: // while I'd like to do auto detection based on join directions, etc.
397: // the distinguished column / table / etc names forces our hand
398: // esp for OpenJPA custom mappings.
399: FieldMapping field = (FieldMapping) fmd;
400: switch (strategy) {
401: case ONE_ONE:
402: case MANY_ONE:
403: serializeColumns(field.getValueInfo(), ColType.JOIN, field
404: .getMappingInfo().getTableName(), null, fmd);
405: return;
406: case ONE_MANY:
407: if (field.getMappingInfo().getJoinDirection() == MappingInfo.JOIN_NONE) {
408: serializeColumns(field.getElementMapping()
409: .getValueInfo(), ColType.JOIN, null, null, fmd);
410: return;
411: }
412: // else no break
413: case MANY_MANY:
414: if (field.getMappingInfo().hasSchemaComponents()
415: || field.getElementMapping().getValueInfo()
416: .hasSchemaComponents()) {
417: AnnotationBuilder abJoinTbl = addAnnotation(
418: JoinTable.class, fmd);
419: String table = field.getMappingInfo().getTableName();
420: if (table != null) {
421: int index = table.indexOf('.');
422: if (index < 0)
423: abJoinTbl.add("name", table);
424: else {
425: abJoinTbl.add("schema", table.substring(0,
426: index));
427: abJoinTbl.add("name", table
428: .substring(index + 1));
429: }
430: }
431: serializeColumns(field.getMappingInfo(), ColType.JOIN,
432: null, abJoinTbl, null);
433: serializeColumns(field.getElementMapping()
434: .getValueInfo(), ColType.INVERSE, null,
435: abJoinTbl, null);
436: }
437: return;
438: }
439:
440: serializeColumns(field.getValueInfo(), ColType.COL, field
441: .getMappingInfo().getTableName(), null, fmd);
442: if (strategy == PersistenceStrategy.BASIC && isLob(field)) {
443: addAnnotation(Lob.class, fmd);
444: }
445: TemporalType temporal = getTemporal(field);
446: if (temporal != null) {
447: addAnnotation(Temporal.class, fmd).add(null, temporal);
448: }
449:
450: EnumType enumType = getEnumType(field);
451: if (enumType != null && enumType != EnumType.ORDINAL) {
452: addAnnotation(Enumerated.class, fmd).add(null, enumType);
453: }
454: }
455:
456: /**
457: * Determine if the field is a lob.
458: */
459: private boolean isLob(FieldMapping field) {
460: for (Column col : (List<Column>) field.getValueInfo()
461: .getColumns())
462: if (col.getType() == Types.BLOB
463: || col.getType() == Types.CLOB)
464: return true;
465: return false;
466: }
467:
468: /**
469: * Return field's temporal type.
470: */
471: private TemporalType getTemporal(FieldMapping field) {
472: if (field.getDeclaredTypeCode() != JavaTypes.DATE
473: && field.getDeclaredTypeCode() != JavaTypes.CALENDAR)
474: return null;
475:
476: DBDictionary dict = ((JDBCConfiguration) getConfiguration())
477: .getDBDictionaryInstance();
478: int def = dict.getJDBCType(field.getTypeCode(), false);
479: for (Column col : (List<Column>) field.getValueInfo()
480: .getColumns()) {
481: if (col.getType() == def)
482: continue;
483: switch (col.getType()) {
484: case Types.DATE:
485: return TemporalType.DATE;
486: case Types.TIME:
487: return TemporalType.TIME;
488: case Types.TIMESTAMP:
489: return TemporalType.TIMESTAMP;
490: }
491: }
492: return null;
493: }
494:
495: /**
496: * Return enum type for the field.
497: */
498: protected EnumType getEnumType(FieldMapping field) {
499: if (field.getDeclaredTypeCode() != JavaTypes.OBJECT)
500: return null;
501: if (!(field.getHandler() instanceof EnumValueHandler))
502: return null;
503: return ((EnumValueHandler) field.getHandler())
504: .getStoreOrdinal() ? EnumType.ORDINAL : EnumType.STRING;
505: }
506:
507: /**
508: * Serialize the columns in the given mapping info.
509: */
510: private void serializeColumns(MappingInfo info, ColType type,
511: String secondary, AnnotationBuilder ab, Object meta) {
512: List<Column> cols = (List<Column>) info.getColumns();
513: if (cols == null)
514: return;
515: AnnotationBuilder abContainer = ab;
516: if (cols.size() > 1) {
517: Class grpType = type.getColumnGroupAnnotationType();
518: if (null != grpType) {
519: AnnotationBuilder abGrp = newAnnotationBuilder(grpType);
520: if (null == ab)
521: addAnnotation(abGrp, meta);
522: else
523: ab.add(null, abGrp);
524: abContainer = abGrp;
525: }
526: }
527: for (Column col : cols)
528: serializeColumn(col, type, secondary,
529: info.getUnique() != null, abContainer, meta);
530: }
531:
532: /**
533: * Serialize a single column.
534: */
535: private void serializeColumn(Column col, ColType type,
536: String secondary, boolean unique, AnnotationBuilder ab,
537: Object meta) {
538: FieldMetaData fmd = meta instanceof FieldMetaData ? (FieldMetaData) meta
539: : null;
540: AnnotationBuilder abCol = newAnnotationBuilder(type
541: .getColumnAnnotationType());
542: if (col.getName() != null
543: && (null == fmd || !col.getName().equalsIgnoreCase(
544: fmd.getName())))
545: abCol.add("name", col.getName());
546: if (col.getTypeName() != null)
547: abCol.add("columnDefinition", col.getTypeName());
548: if (col.getTarget() != null
549: && (type == ColType.JOIN || type == ColType.INVERSE || type == ColType.PK_JOIN))
550: abCol.add("referencedColumnName", col.getTarget());
551: if (type == ColType.COL || type == ColType.JOIN
552: || type == ColType.PK_JOIN) {
553: if (unique)
554: abCol.add("unique", true);
555: if (col.isNotNull())
556: abCol.add("nullable", false);
557: if (col.getFlag(Column.FLAG_UNINSERTABLE))
558: abCol.add("insertable", false);
559: if (col.getFlag(Column.FLAG_UNUPDATABLE))
560: abCol.add("updatable", false);
561: if (secondary != null)
562: abCol.add("table", secondary);
563:
564: if (type == ColType.COL) {
565: if (col.getSize() > 0 && col.getSize() != 255)
566: abCol.add("length", col.getSize());
567: if (col.getDecimalDigits() != 0)
568: abCol.add("scale", col.getDecimalDigits());
569: }
570: }
571:
572: if (type != ColType.COL || abCol.hasComponents()) {
573: if (null != ab) {
574: String key = null;
575: if (ab.getType() == JoinTable.class) {
576: switch (type) {
577: case JOIN:
578: key = "joinColumns";
579: break;
580: case INVERSE:
581: key = "inverseJoinColumns";
582: break;
583: }
584: }
585: ab.add(key, abCol);
586: } else {
587: addAnnotation(abCol, meta);
588: }
589: }
590: }
591:
592: private void serializeUniqueConstraint(Unique unique,
593: AnnotationBuilder ab) {
594: StringBuilder sb = new StringBuilder();
595: Column[] columns = unique.getColumns();
596: for (Column column : columns) {
597: if (sb.length() > 0)
598: sb.append(", ");
599: sb.append(column.getName());
600: }
601: if (columns.length > 1)
602: sb.insert(0, "{").append("}");
603: ab.add("columnNames", sb.toString());
604: }
605:
606: @Override
607: protected SerializationComparator newSerializationComparator() {
608: return new AnnotationPersistenceMappingSerializer.MappingSerializationComparator();
609: }
610:
611: @Override
612: protected void addSystemMappingElements(Collection toSerialize) {
613: if (isQueryMode())
614: toSerialize.addAll(getQueryResultMappings(null));
615: }
616:
617: @Override
618: protected int type(Object o) {
619: int type = super .type(o);
620: if (type == -1 && o instanceof QueryResultMapping)
621: return TYPE_RESULTMAP;
622: return type;
623: }
624:
625: /**
626: * Return the result set mappings for the given scope.
627: */
628: private List<QueryResultMapping> getQueryResultMappings(
629: ClassMetaData cm) {
630: if (_results == null || _results.isEmpty())
631: return (List<QueryResultMapping>) Collections.EMPTY_LIST;
632:
633: List<QueryResultMapping> result = null;
634: for (int i = 0; i < _results.size(); i++) {
635: QueryResultMapping element = _results.get(i);
636: if ((cm == null && element.getSourceScope() != null)
637: || (cm != null && element.getSourceScope() != cm
638: .getDescribedType()))
639: continue;
640:
641: if (result == null)
642: result = new ArrayList<QueryResultMapping>(_results
643: .size()
644: - i);
645: result.add(element);
646: }
647: return (result == null) ? (List<QueryResultMapping>) Collections.EMPTY_LIST
648: : result;
649: }
650:
651: @Override
652: protected void serializeSystemMappingElement(Object obj) {
653: if (obj instanceof QueryResultMapping)
654: serializeQueryResultMapping((QueryResultMapping) obj, null);
655: }
656:
657: @Override
658: protected void serializeQueryMappings(ClassMetaData meta) {
659: for (QueryResultMapping res : getQueryResultMappings(meta))
660: serializeQueryResultMapping(res, meta);
661: }
662:
663: /**
664: * Serialize given result set mapping.
665: */
666: private void serializeQueryResultMapping(QueryResultMapping meta,
667: ClassMetaData clsmeta) {
668: AnnotationBuilder ab = addAnnotation(SqlResultSetMapping.class,
669: meta);
670: if (null != clsmeta)
671: addAnnotation(ab, clsmeta);
672: ab.add("name", meta.getName());
673: for (QueryResultMapping.PCResult pc : meta.getPCResults()) {
674: AnnotationBuilder abEntRes = newAnnotationBuilder(EntityResult.class);
675: ab.add("entities", abEntRes);
676: abEntRes.add("entityClass", pc.getCandidateType());
677: Object discrim = pc.getMapping(pc.DISCRIMINATOR);
678: if (discrim != null)
679: abEntRes.add("discriminatorColumn", discrim.toString());
680:
681: for (String path : pc.getMappingPaths()) {
682: AnnotationBuilder abFldRes = newAnnotationBuilder(FieldResult.class);
683: abEntRes.add("fields", abFldRes);
684: abFldRes.add("name", path);
685: abFldRes.add("column", pc.getMapping(path).toString());
686: }
687: }
688: for (Object col : meta.getColumnResults()) {
689: AnnotationBuilder abColRes = newAnnotationBuilder(ColumnResult.class);
690: abColRes.add("name", col.toString());
691: }
692: }
693:
694: @Override
695: protected void serializeSequence(SequenceMetaData meta) {
696: if (SequenceMapping.IMPL_VALUE_TABLE.equals(meta
697: .getSequencePlugin())) {
698: super .serializeSequence(meta);
699: return;
700: }
701:
702: AnnotationBuilder abTblGen = addAnnotation(
703: TableGenerator.class, meta);
704: SequenceMapping seq = (SequenceMapping) meta;
705: abTblGen.add("name", seq.getName());
706: String table = seq.getTable();
707: if (table != null) {
708: int dotIdx = table.indexOf('.');
709: if (dotIdx == -1)
710: abTblGen.add("table", table);
711: else {
712: abTblGen.add("table", table.substring(dotIdx + 1));
713: abTblGen.add("schema", table.substring(0, dotIdx));
714: }
715: }
716: if (!StringUtils.isEmpty(seq.getPrimaryKeyColumn()))
717: abTblGen.add("pkColumnName", seq.getPrimaryKeyColumn());
718: if (!StringUtils.isEmpty(seq.getSequenceColumn()))
719: abTblGen.add("valueColumnName", seq.getSequenceColumn());
720: if (!StringUtils.isEmpty(seq.getPrimaryKeyValue()))
721: abTblGen.add("pkColumnValue", seq.getPrimaryKeyValue());
722: if (seq.getAllocate() != 50 && seq.getAllocate() != -1)
723: abTblGen.add("allocationSize", seq.getAllocate() + "");
724: if (seq.getInitialValue() != 0 && seq.getInitialValue() != -1)
725: abTblGen.add("initialValue", seq.getInitialValue() + "");
726: }
727:
728: /**
729: * Column types serialized under different names.
730: */
731: private static enum ColType {
732:
733: COL, JOIN, INVERSE, PK_JOIN, DISC;
734:
735: private Class<? extends Annotation> getColumnAnnotationType() {
736: switch (this ) {
737: case COL:
738: return javax.persistence.Column.class;
739: case JOIN:
740: case INVERSE:
741: return JoinColumn.class;
742: case PK_JOIN:
743: return PrimaryKeyJoinColumn.class;
744: case DISC:
745: return DiscriminatorColumn.class;
746: }
747: return null;
748: }
749:
750: private Class<? extends Annotation> getColumnGroupAnnotationType() {
751: switch (this ) {
752: case JOIN:
753: case INVERSE:
754: return JoinColumns.class;
755: case PK_JOIN:
756: return PrimaryKeyJoinColumns.class;
757: }
758: return null;
759: }
760:
761: }
762:
763: /**
764: * Extends {@link SerializationComparator} for store-specific tags such
765: * as <sql-result-set-mapping>.
766: *
767: * @author Pinaki Poddar
768: */
769: protected class MappingSerializationComparator extends
770: SerializationComparator {
771:
772: protected int compareUnknown(Object o1, Object o2) {
773: if (!(o1 instanceof QueryResultMapping))
774: return super .compareUnknown(o1, o2);
775:
776: QueryResultMapping res1 = (QueryResultMapping) o1;
777: QueryResultMapping res2 = (QueryResultMapping) o2;
778:
779: // system scope before class scope
780: Object scope1 = res1.getSourceScope();
781: Object scope2 = res2.getSourceScope();
782: if (scope1 == null && scope2 != null)
783: return -1;
784: if (scope1 != null && scope2 == null)
785: return 1;
786:
787: // compare on listing index, or if none/same, use name
788: int listingIndex1 = res1.getListingIndex();
789: int listingIndex2 = res2.getListingIndex();
790: if (listingIndex1 != listingIndex2)
791: return listingIndex1 - listingIndex2;
792: return res1.getName().compareTo(res2.getName());
793: }
794: }
795: }
|