| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.openjpa.persistence.jdbc; |
| |
| import java.lang.annotation.Annotation; |
| import java.sql.Types; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| |
| import javax.persistence.ColumnResult; |
| import javax.persistence.DiscriminatorColumn; |
| import javax.persistence.DiscriminatorValue; |
| import javax.persistence.EntityResult; |
| import javax.persistence.EnumType; |
| import javax.persistence.Enumerated; |
| import javax.persistence.FieldResult; |
| import javax.persistence.Inheritance; |
| import javax.persistence.InheritanceType; |
| import javax.persistence.JoinColumn; |
| import javax.persistence.JoinColumns; |
| import javax.persistence.JoinTable; |
| import javax.persistence.Lob; |
| import javax.persistence.PrimaryKeyJoinColumn; |
| import javax.persistence.PrimaryKeyJoinColumns; |
| import javax.persistence.SecondaryTable; |
| import javax.persistence.SqlResultSetMapping; |
| import javax.persistence.Table; |
| import javax.persistence.TableGenerator; |
| import javax.persistence.Temporal; |
| import javax.persistence.TemporalType; |
| import javax.persistence.UniqueConstraint; |
| |
| import org.apache.openjpa.jdbc.conf.JDBCConfiguration; |
| import org.apache.openjpa.jdbc.meta.ClassMapping; |
| import org.apache.openjpa.jdbc.meta.ClassMappingInfo; |
| import org.apache.openjpa.jdbc.meta.DiscriminatorMappingInfo; |
| import org.apache.openjpa.jdbc.meta.FieldMapping; |
| import org.apache.openjpa.jdbc.meta.MappingInfo; |
| import org.apache.openjpa.jdbc.meta.MappingRepository; |
| import org.apache.openjpa.jdbc.meta.QueryResultMapping; |
| import org.apache.openjpa.jdbc.meta.QueryResultMapping.PCResult; |
| import org.apache.openjpa.jdbc.meta.SequenceMapping; |
| import org.apache.openjpa.jdbc.meta.ValueMappingInfo; |
| import org.apache.openjpa.jdbc.meta.strats.EnumValueHandler; |
| import org.apache.openjpa.jdbc.meta.strats.FlatClassStrategy; |
| import org.apache.openjpa.jdbc.meta.strats.FullClassStrategy; |
| import org.apache.openjpa.jdbc.meta.strats.VerticalClassStrategy; |
| import org.apache.openjpa.jdbc.schema.Column; |
| import org.apache.openjpa.jdbc.schema.Unique; |
| import org.apache.openjpa.jdbc.sql.DBDictionary; |
| import org.apache.openjpa.lib.util.ClassUtil; |
| import org.apache.openjpa.lib.util.StringUtil; |
| import org.apache.openjpa.meta.ClassMetaData; |
| import org.apache.openjpa.meta.FieldMetaData; |
| import org.apache.openjpa.meta.JavaTypes; |
| import org.apache.openjpa.meta.MetaDataModes; |
| import org.apache.openjpa.meta.MetaDataRepository; |
| import org.apache.openjpa.meta.SequenceMetaData; |
| import org.apache.openjpa.persistence.AnnotationBuilder; |
| import org.apache.openjpa.persistence.AnnotationPersistenceMetaDataSerializer; |
| import org.apache.openjpa.persistence.PersistenceStrategy; |
| |
| |
| /** |
| * Serializes persistence mappings as annotations. |
| * |
| * @since 1.0.0 |
| * @author Steve Kim |
| * @author Gokhan Ergul |
| */ |
| public class AnnotationPersistenceMappingSerializer |
| extends AnnotationPersistenceMetaDataSerializer { |
| |
| private static final int TYPE_RESULTMAP = TYPE_QUERY + 1; |
| |
| private List<QueryResultMapping> _results = null; |
| private boolean _sync = false; |
| |
| private Map<QueryResultMapping, List<AnnotationBuilder>> _rsmAnnos = null; |
| |
| /** |
| * Constructor. Supply configuration. |
| */ |
| public AnnotationPersistenceMappingSerializer(JDBCConfiguration conf) { |
| super(conf); |
| } |
| |
| /** |
| * Whether to automatically synchronize mapping info with data available |
| * from mapped components before serialization. Defaults to false. |
| */ |
| public boolean getSyncMappingInfo() { |
| return _sync; |
| } |
| |
| /** |
| * Whether to automatically synchronize mapping info with data available |
| * from mapped components before serialization. Defaults to false. |
| */ |
| public void setSyncMappingInfo(boolean sync) { |
| _sync = sync; |
| } |
| |
| /** |
| * Adds the given result set mapping to local cache. |
| */ |
| public void addQueryResultMapping(QueryResultMapping meta) { |
| if (_results == null) |
| _results = new ArrayList<>(); |
| _results.add(meta); |
| } |
| |
| /** |
| * Removes given result set mapping from the local cache. |
| */ |
| public boolean removeQueryResultMapping(QueryResultMapping meta) { |
| return _results != null && _results.remove(meta); |
| } |
| |
| @Override |
| public void addAll(MetaDataRepository repos) { |
| super.addAll(repos); |
| for (QueryResultMapping res : ((MappingRepository) repos) |
| .getQueryResultMappings()) |
| addQueryResultMapping(res); |
| } |
| |
| @Override |
| public boolean removeAll(MetaDataRepository repos) { |
| boolean removed = super.removeAll(repos); |
| for (QueryResultMapping res : ((MappingRepository) repos) |
| .getQueryResultMappings()) |
| removed |= removeQueryResultMapping(res); |
| return removed; |
| } |
| |
| @Override |
| public void clear() { |
| super.clear(); |
| if (_results != null) |
| _results.clear(); |
| } |
| |
| /** |
| * Add an annotation builder to list of builders for the specified |
| * class metadata. |
| */ |
| protected void addAnnotation(AnnotationBuilder ab, QueryResultMapping meta) |
| { |
| if (_rsmAnnos == null) |
| _rsmAnnos = new HashMap<>(); |
| List<AnnotationBuilder> list = _rsmAnnos.get(meta); |
| if (list == null) { |
| list = new ArrayList<>(); |
| _rsmAnnos.put(meta, list); |
| } |
| list.add(ab); |
| } |
| |
| /** |
| * Creates an an annotation builder for the specified class metadata |
| * and adds it to list of builders. |
| */ |
| protected AnnotationBuilder addAnnotation( |
| Class<? extends Annotation> annType, QueryResultMapping meta) { |
| AnnotationBuilder ab = newAnnotationBuilder(annType); |
| if (meta == null) |
| return ab; |
| addAnnotation(ab, meta); |
| return ab; |
| } |
| |
| |
| @Override |
| protected void serializeClass(ClassMetaData meta) { |
| if (_sync && isMappingMode() && meta instanceof ClassMapping) { |
| // sync if resolved and mapped |
| ClassMapping cls = (ClassMapping) meta; |
| if ((cls.getResolve() & MetaDataModes.MODE_MAPPING) != 0 && |
| cls.isMapped()) { |
| cls.syncMappingInfo(); |
| cls.getDiscriminator().syncMappingInfo(); |
| cls.getVersion().syncMappingInfo(); |
| FieldMapping[] fields; |
| if (cls.getEmbeddingMetaData() == null) |
| fields = cls.getDefinedFieldMappings(); |
| else |
| fields = cls.getFieldMappings(); |
| for (FieldMapping f : fields) |
| f.syncMappingInfo(); |
| } |
| } |
| super.serializeClass(meta); |
| } |
| |
| @Override |
| protected void serializeClassMappingContent(ClassMetaData mapping) { |
| ClassMapping cls = (ClassMapping) mapping; |
| ClassMappingInfo info = cls.getMappingInfo(); |
| AnnotationBuilder abTable = addAnnotation(Table.class, mapping); |
| serializeTable(info.getTableName(), ClassUtil.getClassName(mapping.getDescribedType()), null, |
| info.getUniques(info.getTableName()), abTable); |
| serializeColumns(info, ColType.PK_JOIN, null, abTable, cls); |
| for (String second : info.getSecondaryTableNames()) { |
| AnnotationBuilder abSecTable = |
| addAnnotation(SecondaryTable.class, mapping); |
| serializeTable(second, null, info, info.getUniques(second), |
| abSecTable); |
| } |
| } |
| |
| @Override |
| protected void serializeInheritanceContent(ClassMetaData mapping) { |
| ClassMapping cls = (ClassMapping) mapping; |
| ClassMappingInfo info = cls.getMappingInfo(); |
| DiscriminatorMappingInfo dinfo = cls.getDiscriminator() |
| .getMappingInfo(); |
| String strat = info.getHierarchyStrategy(); |
| if (null == strat) |
| return; |
| String itypecls = ClassUtil.getClassName(InheritanceType.class); |
| AnnotationBuilder abInheritance = |
| addAnnotation(Inheritance.class, mapping); |
| if (FlatClassStrategy.ALIAS.equals(strat)) |
| abInheritance.add("strategy", itypecls + ".SINGLE_TABLE"); |
| else if (VerticalClassStrategy.ALIAS.equals(strat)) |
| abInheritance.add("strategy", itypecls + ".JOINED"); |
| else if (FullClassStrategy.ALIAS.equals(strat)) |
| abInheritance.add("strategy", itypecls + ".TABLE_PER_CLASS"); |
| if (dinfo.getValue() != null) { |
| AnnotationBuilder abDiscVal = |
| addAnnotation(DiscriminatorValue.class, mapping); |
| abDiscVal.add(null, dinfo.getValue()); |
| } |
| AnnotationBuilder abDiscCol = |
| addAnnotation(DiscriminatorColumn.class, mapping); |
| serializeColumns(dinfo, ColType.DISC, null, abDiscCol, null); |
| } |
| |
| /** |
| * Serialize table optionally listing primary-key-joins stored |
| * in the given {@link org.apache.openjpa.jdbc.meta.ClassMappingInfo}. |
| */ |
| private void serializeTable(String table, String defaultName, |
| ClassMappingInfo secondaryInfo, Unique[] uniques, |
| AnnotationBuilder ab) { |
| List<Column> cols = null; |
| if (secondaryInfo != null) |
| cols = secondaryInfo.getSecondaryTableJoinColumns |
| (table); |
| |
| boolean print = (cols != null && cols.size() > 0) || |
| (uniques != null && uniques.length > 0); |
| if (table != null |
| && (defaultName == null || !defaultName.equals(table))) { |
| print = true; |
| int index = table.indexOf('.'); |
| if (index < 0) |
| ab.add("name", table); |
| else { |
| Map<String, ClassMetaData> classMetaData = getClassMetaData(); |
| Object[] keySet = null; |
| if(classMetaData != null) |
| { |
| keySet = classMetaData.keySet().toArray(); |
| } |
| if((keySet != null) && (keySet.length > 0) && classMetaData.get(keySet[0]).getUseSchemaElement()) |
| { |
| ab.add("schema", table.substring(0, index)); |
| } |
| ab.add("name", table.substring(index + 1)); |
| } |
| } |
| if (print) { |
| if (cols != null) { |
| for (Column col : cols) |
| serializeColumn(col, ColType.PK_JOIN, |
| null, false, ab, null); |
| } |
| if (uniques != null) { |
| for (Unique unique: uniques) { |
| AnnotationBuilder abUniqueConst = |
| newAnnotationBuilder(UniqueConstraint.class); |
| serializeUniqueConstraint(unique, abUniqueConst); |
| ab.add("uniqueConstraints", abUniqueConst); |
| } |
| } |
| } |
| } |
| |
| @Override |
| protected boolean serializeAttributeOverride(FieldMetaData fmd, |
| FieldMetaData orig) { |
| if (orig == null || fmd == orig) |
| return false; |
| |
| FieldMapping field = (FieldMapping) fmd; |
| FieldMapping field2 = (FieldMapping) orig; |
| if (field.getMappingInfo().hasSchemaComponents() |
| || field2.getMappingInfo().hasSchemaComponents()) |
| return true; |
| |
| ValueMappingInfo info = field.getValueInfo(); |
| List<Column> cols = info.getColumns(); |
| if (cols == null || cols.size() == 0) |
| return false; |
| ValueMappingInfo info2 = field2.getValueInfo(); |
| List<Column> cols2 = info2.getColumns(); |
| if (cols2 == null || cols2.size() != cols.size()) |
| return true; |
| if (cols.size() != 1) |
| return true; |
| |
| Column col; |
| Column col2; |
| for (int i = 0; i < cols.size(); i++) { |
| col = cols.get(i); |
| col2 = cols2.get(i); |
| if (!Objects.equals(col.getName(), col2.getName())) |
| return true; |
| if (!Objects.equals(col.getTypeName(), col2.getTypeName())) |
| return true; |
| if (col.getSize() != col2.getSize()) |
| return true; |
| if (col.getDecimalDigits() != col2.getDecimalDigits()) |
| return true; |
| if (col.getFlag(Column.FLAG_UNINSERTABLE) |
| != col2.getFlag(Column.FLAG_UNINSERTABLE)) |
| return true; |
| if (col.getFlag(Column.FLAG_UNUPDATABLE) |
| != col2.getFlag(Column.FLAG_UNUPDATABLE)) |
| return true; |
| } |
| return false; |
| } |
| |
| @Override |
| protected void serializeAttributeOverrideMappingContent(FieldMetaData fmd, |
| FieldMetaData orig, AnnotationBuilder ab) { |
| FieldMapping fm = (FieldMapping) fmd; |
| serializeColumns(fm.getValueInfo(), ColType.COL, fm.getMappingInfo() |
| .getTableName(), ab, fmd); |
| } |
| |
| @Override |
| protected PersistenceStrategy getStrategy(FieldMetaData fmd) { |
| PersistenceStrategy strat = super.getStrategy(fmd); |
| FieldMapping field = (FieldMapping) fmd; |
| switch (strat) { |
| case MANY_MANY: |
| // we can differentiate a one-many by the fact that there is no |
| // secondary table join, or the fk is unique |
| if (field.getMappedBy() == null |
| && (field.getMappingInfo().getJoinDirection() |
| == MappingInfo.JOIN_NONE |
| || field.getElementMapping().getValueInfo().getUnique() |
| != null)) |
| return PersistenceStrategy.ONE_MANY; |
| break; |
| case MANY_ONE: |
| // inverse join cols or unique fk? |
| if (field.getValueInfo().getJoinDirection() |
| == MappingInfo.JOIN_INVERSE |
| || field.getValueInfo().getUnique() != null) |
| return PersistenceStrategy.ONE_ONE; |
| |
| // scan for primary-key-join-column |
| List<Column> cols = field.getValueInfo().getColumns(); |
| boolean pkJoin = cols != null && cols.size() > 0; |
| for (int i = 0; pkJoin && i < cols.size(); i++) |
| pkJoin = cols.get(i).getFlag(Column.FLAG_PK_JOIN); |
| if (pkJoin) |
| return PersistenceStrategy.ONE_ONE; |
| break; |
| } |
| return strat; |
| } |
| |
| @Override |
| protected void serializeFieldMappingContent(FieldMetaData fmd, |
| PersistenceStrategy strategy, AnnotationBuilder ab) { |
| if (fmd.getMappedBy() != null) |
| return; |
| |
| // while I'd like to do auto detection based on join directions, etc. |
| // the distinguished column / table / etc names forces our hand |
| // esp for OpenJPA custom mappings. |
| FieldMapping field = (FieldMapping) fmd; |
| switch (strategy) { |
| case ONE_ONE: |
| case MANY_ONE: |
| serializeColumns(field.getValueInfo(), ColType.JOIN, |
| field.getMappingInfo().getTableName(), null, fmd); |
| return; |
| case ONE_MANY: |
| if (field.getMappingInfo().getJoinDirection() == |
| MappingInfo.JOIN_NONE) { |
| serializeColumns(field.getElementMapping().getValueInfo(), |
| ColType.JOIN, null, null, fmd); |
| return; |
| } |
| // else no break |
| case MANY_MANY: |
| if (field.getMappingInfo().hasSchemaComponents() |
| || field.getElementMapping().getValueInfo() |
| .hasSchemaComponents()) { |
| AnnotationBuilder abJoinTbl = |
| addAnnotation(JoinTable.class, fmd); |
| String table = field.getMappingInfo().getTableName(); |
| if (table != null) { |
| int index = table.indexOf('.'); |
| if (index < 0) |
| abJoinTbl.add("name", table); |
| else { |
| abJoinTbl.add("schema", table.substring(0, index)); |
| abJoinTbl.add("name", table.substring(index + 1)); |
| } |
| } |
| serializeColumns(field.getMappingInfo(), |
| ColType.JOIN, null, abJoinTbl, null); |
| serializeColumns(field.getElementMapping().getValueInfo(), |
| ColType.INVERSE, null, abJoinTbl, null); |
| } |
| return; |
| } |
| |
| serializeColumns(field.getValueInfo(), ColType.COL, |
| field.getMappingInfo().getTableName(), null, fmd); |
| if (strategy == PersistenceStrategy.BASIC && isLob(field)) { |
| addAnnotation(Lob.class, fmd); |
| } |
| TemporalType temporal = getTemporal(field); |
| if (temporal != null) { |
| addAnnotation(Temporal.class, fmd). |
| add(null, temporal); |
| } |
| |
| EnumType enumType = getEnumType(field); |
| if (enumType != null && enumType != EnumType.ORDINAL) { |
| addAnnotation(Enumerated.class, fmd). |
| add(null, enumType); |
| } |
| } |
| |
| /** |
| * Determine if the field is a lob. |
| */ |
| private boolean isLob(FieldMapping field) { |
| for (Column col : field.getValueInfo().getColumns()) |
| if (col.getType() == Types.BLOB || col.getType() == Types.CLOB) |
| return true; |
| return false; |
| } |
| |
| /** |
| * Return field's temporal type. |
| */ |
| private TemporalType getTemporal(FieldMapping field) { |
| if (field.getDeclaredTypeCode() != JavaTypes.DATE |
| && field.getDeclaredTypeCode() != JavaTypes.CALENDAR) |
| { |
| return null; |
| } |
| |
| DBDictionary dict = ((JDBCConfiguration) getConfiguration()) |
| .getDBDictionaryInstance(); |
| int def = dict.getJDBCType(field.getTypeCode(), false); |
| for (Column col : field.getValueInfo().getColumns()) { |
| if (col.getType() == def) { |
| continue; |
| } |
| switch (col.getType()) { |
| case Types.DATE: |
| return TemporalType.DATE; |
| case Types.TIME: |
| return TemporalType.TIME; |
| case Types.TIMESTAMP: |
| return TemporalType.TIMESTAMP; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Return enum type for the field. |
| */ |
| protected EnumType getEnumType(FieldMapping field) { |
| if (field.getDeclaredTypeCode() != JavaTypes.OBJECT |
| && field.getDeclaredTypeCode() != JavaTypes.ENUM) |
| { |
| return null; |
| } |
| if (!(field.getHandler() instanceof EnumValueHandler)) { |
| return null; |
| } |
| return ((EnumValueHandler) field.getHandler()).getStoreOrdinal() |
| ? EnumType.ORDINAL : EnumType.STRING; |
| } |
| |
| /** |
| * Serialize the columns in the given mapping info. |
| */ |
| private void serializeColumns(MappingInfo info, ColType type, |
| String secondary, AnnotationBuilder ab, Object meta) { |
| List<Column> cols = info.getColumns(); |
| if (cols == null) { |
| return; |
| } |
| AnnotationBuilder abContainer = ab; |
| if (cols.size() > 1) { |
| Class<? extends Annotation> grpType = type.getColumnGroupAnnotationType(); |
| if (null != grpType) { |
| AnnotationBuilder abGrp = newAnnotationBuilder(grpType); |
| if (null == ab) { |
| addAnnotation(abGrp, meta); |
| } else { |
| ab.add(null, abGrp); |
| } |
| abContainer = abGrp; |
| } |
| } |
| for (Column col : cols) { |
| serializeColumn(col, type, secondary, |
| info.getUnique() != null, abContainer, meta); |
| } |
| } |
| |
| /** |
| * Serialize a single column. |
| */ |
| private void serializeColumn(Column col, ColType type, String secondary, |
| boolean unique, AnnotationBuilder ab, Object meta) { |
| FieldMetaData fmd = meta instanceof FieldMetaData ? |
| (FieldMetaData) meta : null; |
| AnnotationBuilder abCol = newAnnotationBuilder( |
| type.getColumnAnnotationType()); |
| if (col.getName() != null && (null == fmd || |
| !col.getName().equalsIgnoreCase(fmd.getName()))) |
| abCol.add("name", col.getName()); |
| if (col.getTypeName() != null) |
| abCol.add("columnDefinition", col.getTypeName()); |
| if (col.getTarget() != null |
| && (type == ColType.JOIN || type == ColType.INVERSE |
| || type == ColType.PK_JOIN)) |
| abCol.add("referencedColumnName", col.getTarget()); |
| if (type == ColType.COL || type == ColType.JOIN |
| || type == ColType.PK_JOIN) { |
| if (unique) |
| abCol.add("unique", true); |
| if (col.isNotNull()) |
| abCol.add("nullable", false); |
| if (col.getFlag(Column.FLAG_UNINSERTABLE)) |
| abCol.add("insertable", false); |
| if (col.getFlag(Column.FLAG_UNUPDATABLE)) |
| abCol.add("updatable", false); |
| if (secondary != null) |
| abCol.add("table", secondary); |
| |
| if (type == ColType.COL) { |
| if (col.getSize() > 0 && col.getSize() != 255) |
| abCol.add("length", col.getSize()); |
| if (col.getDecimalDigits() != 0) |
| abCol.add("scale", col.getDecimalDigits()); |
| } |
| } |
| |
| if (type != ColType.COL || abCol.hasComponents()) { |
| if (null != ab) { |
| String key = null; |
| if (ab.getType() == JoinTable.class) { |
| switch(type) { |
| case JOIN: |
| key = "joinColumns"; |
| break; |
| case INVERSE: |
| key = "inverseJoinColumns"; |
| break; |
| } |
| } |
| ab.add(key, abCol); |
| } else { |
| addAnnotation(abCol, meta); |
| } |
| } |
| } |
| |
| private void serializeUniqueConstraint(Unique unique, |
| AnnotationBuilder ab) { |
| StringBuilder sb = new StringBuilder(); |
| Column[] columns = unique.getColumns(); |
| for (Column column:columns) { |
| if (sb.length() > 0) |
| sb.append(", "); |
| sb.append(column.getName()); |
| } |
| if (columns.length > 1) |
| sb.insert(0, "{").append("}"); |
| ab.add("columnNames", sb.toString()); |
| if (StringUtil.isNotEmpty(unique.getName())) { |
| ab.add("name", unique.getName()); |
| } |
| } |
| |
| @Override |
| protected SerializationComparator newSerializationComparator() { |
| return new AnnotationPersistenceMappingSerializer. |
| MappingSerializationComparator(); |
| } |
| |
| @Override |
| protected void addSystemMappingElements(Collection toSerialize) { |
| if (isQueryMode()) |
| toSerialize.addAll(getQueryResultMappings(null)); |
| } |
| |
| @Override |
| protected int type(Object o) { |
| int type = super.type(o); |
| if (type == -1 && o instanceof QueryResultMapping) |
| return TYPE_RESULTMAP; |
| return type; |
| } |
| |
| /** |
| * Return the result set mappings for the given scope. |
| */ |
| private List<QueryResultMapping> getQueryResultMappings(ClassMetaData cm) { |
| if (_results == null || _results.isEmpty()) |
| return Collections.EMPTY_LIST; |
| |
| List<QueryResultMapping> result = null; |
| for (int i = 0; i < _results.size(); i++) { |
| QueryResultMapping element = _results.get(i); |
| if ((cm == null && element.getSourceScope() != null) || (cm != null |
| && element.getSourceScope() != cm.getDescribedType())) |
| continue; |
| |
| if (result == null) |
| result = new ArrayList<>(_results.size() - i); |
| result.add(element); |
| } |
| return (result == null) |
| ? (List<QueryResultMapping>) Collections.EMPTY_LIST : result; |
| } |
| |
| @Override |
| protected void serializeSystemMappingElement(Object obj) { |
| if (obj instanceof QueryResultMapping) |
| serializeQueryResultMapping((QueryResultMapping) obj, null); |
| } |
| |
| @Override |
| protected void serializeQueryMappings(ClassMetaData meta) { |
| for (QueryResultMapping res : getQueryResultMappings(meta)) |
| serializeQueryResultMapping(res, meta); |
| } |
| |
| /** |
| * Serialize given result set mapping. |
| */ |
| private void serializeQueryResultMapping(QueryResultMapping meta, |
| ClassMetaData clsmeta) { |
| AnnotationBuilder ab = addAnnotation(SqlResultSetMapping.class, meta); |
| if (null != clsmeta) |
| addAnnotation(ab, clsmeta); |
| ab.add("name", meta.getName()); |
| for (QueryResultMapping.PCResult pc : meta.getPCResults()) { |
| AnnotationBuilder abEntRes = |
| newAnnotationBuilder(EntityResult.class); |
| ab.add("entities", abEntRes); |
| abEntRes.add("entityClass", pc.getCandidateType()); |
| Object discrim = pc.getMapping(PCResult.DISCRIMINATOR); |
| if (discrim != null) |
| abEntRes.add("discriminatorColumn", discrim.toString()); |
| |
| for (String path : pc.getMappingPaths()) { |
| AnnotationBuilder abFldRes = |
| newAnnotationBuilder(FieldResult.class); |
| abEntRes.add("fields", abFldRes); |
| abFldRes.add("name", path); |
| abFldRes.add("column", pc.getMapping(path).toString()); |
| } |
| } |
| for (Object col : meta.getColumnResults()) { |
| AnnotationBuilder abColRes = |
| newAnnotationBuilder(ColumnResult.class); |
| abColRes.add("name", col.toString()); |
| } |
| } |
| |
| @Override |
| protected void serializeSequence(SequenceMetaData meta) { |
| if (SequenceMapping.IMPL_VALUE_TABLE.equals(meta.getSequencePlugin())) { |
| super.serializeSequence(meta); |
| return; |
| } |
| |
| AnnotationBuilder abTblGen = addAnnotation(TableGenerator.class, meta); |
| SequenceMapping seq = (SequenceMapping) meta; |
| abTblGen.add("name", seq.getName()); |
| String table = seq.getTable(); |
| if (table != null) { |
| int dotIdx = table.indexOf('.'); |
| if (dotIdx == -1) |
| abTblGen.add("table", table); |
| else { |
| abTblGen.add("table", table.substring(dotIdx + 1)); |
| abTblGen.add("schema", table.substring(0, dotIdx)); |
| } |
| } |
| if (!StringUtil.isEmpty(seq.getPrimaryKeyColumn())) |
| abTblGen.add("pkColumnName", seq.getPrimaryKeyColumn()); |
| if (!StringUtil.isEmpty(seq.getSequenceColumn())) |
| abTblGen.add("valueColumnName", seq.getSequenceColumn()); |
| if (!StringUtil.isEmpty(seq.getPrimaryKeyValue())) |
| abTblGen.add("pkColumnValue", seq.getPrimaryKeyValue()); |
| if (seq.getAllocate() != 50 && seq.getAllocate() != -1) |
| abTblGen.add("allocationSize", seq.getAllocate() + ""); |
| if (seq.getInitialValue() != 0 && seq.getInitialValue() != -1) |
| abTblGen.add("initialValue", seq.getInitialValue() + ""); |
| } |
| |
| /** |
| * Column types serialized under different names. |
| */ |
| private enum ColType { |
| |
| COL, |
| JOIN, |
| INVERSE, |
| PK_JOIN, |
| DISC; |
| |
| private Class<? extends Annotation> getColumnAnnotationType() { |
| switch(this) { |
| case COL: |
| return javax.persistence.Column.class; |
| case JOIN: |
| case INVERSE: |
| return JoinColumn.class; |
| case PK_JOIN: |
| return PrimaryKeyJoinColumn.class; |
| case DISC: |
| return DiscriminatorColumn.class; |
| } |
| return null; |
| } |
| |
| private Class<? extends Annotation> getColumnGroupAnnotationType() { |
| switch(this) { |
| case JOIN: |
| case INVERSE: |
| return JoinColumns.class; |
| case PK_JOIN: |
| return PrimaryKeyJoinColumns.class; |
| } |
| return null; |
| } |
| |
| } |
| |
| /** |
| * Extends {@link SerializationComparator} for store-specific tags such |
| * as <sql-result-set-mapping>. |
| * |
| * @author Pinaki Poddar |
| */ |
| protected class MappingSerializationComparator |
| extends SerializationComparator { |
| |
| |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| protected int compareUnknown(Object o1, Object o2) { |
| if (!(o1 instanceof QueryResultMapping)) |
| return super.compareUnknown(o1, o2); |
| |
| QueryResultMapping res1 = (QueryResultMapping) o1; |
| QueryResultMapping res2 = (QueryResultMapping) o2; |
| |
| // system scope before class scope |
| Object scope1 = res1.getSourceScope(); |
| Object scope2 = res2.getSourceScope(); |
| if (scope1 == null && scope2 != null) |
| return -1; |
| if (scope1 != null && scope2 == null) |
| return 1; |
| |
| // compare on listing index, or if none/same, use name |
| int listingIndex1 = res1.getListingIndex(); |
| int listingIndex2 = res2.getListingIndex(); |
| if (listingIndex1 != listingIndex2) |
| return listingIndex1 - listingIndex2; |
| return res1.getName ().compareTo (res2.getName ()); |
| } |
| } |
| } |