| /* |
| * 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 static org.apache.openjpa.meta.MetaDataModes.MODE_MAPPING; |
| |
| import java.sql.Types; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.EnumMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| |
| import javax.persistence.EnumType; |
| import javax.persistence.TemporalType; |
| |
| 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.ValueMappingImpl; |
| 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.meta.SourceTracker; |
| 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.MetaDataRepository; |
| import org.apache.openjpa.meta.SequenceMetaData; |
| import org.apache.openjpa.persistence.PersistenceStrategy; |
| import org.apache.openjpa.persistence.XMLPersistenceMetaDataSerializer; |
| import org.xml.sax.SAXException; |
| |
| /** |
| * Serializes persistence mapping to XML. |
| * |
| * @since 0.4.0 |
| * @author Steve Kim |
| */ |
| public class XMLPersistenceMappingSerializer |
| extends XMLPersistenceMetaDataSerializer { |
| |
| private static final int TYPE_RESULTMAP = TYPE_QUERY + 1; |
| |
| private static final Map<ColType, String> _names; |
| |
| static { |
| _names = new EnumMap<>(ColType.class); |
| _names.put(ColType.COL, "column"); |
| _names.put(ColType.JOIN, "join-column"); |
| _names.put(ColType.INVERSE, "inverse-join-column"); |
| _names.put(ColType.PK_JOIN, "primary-key-join-column"); |
| _names.put(ColType.DISC, "discriminator-column"); |
| } |
| |
| private List<QueryResultMapping> _results = null; |
| private boolean _sync = false; |
| |
| /** |
| * Constructor. Supply configuration. |
| */ |
| public XMLPersistenceMappingSerializer(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(); |
| } |
| |
| protected void addCommments(Object obj) |
| throws SAXException { |
| if (isMappingMode() && !isMetaDataMode()) { |
| if (obj instanceof ClassMapping) |
| obj = ((ClassMapping) obj).getMappingInfo(); |
| else if (obj instanceof FieldMapping) |
| obj = ((FieldMapping) obj).getMappingInfo(); |
| } |
| super.addComments(obj); |
| } |
| |
| @Override |
| protected void serializeClass(ClassMetaData meta, boolean access) |
| throws SAXException { |
| if (_sync && isMappingMode() && meta instanceof ClassMapping) { |
| // sync if resolved and mapped |
| ClassMapping cls = (ClassMapping) meta; |
| if ((cls.getResolve() & 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, access); |
| } |
| |
| @Override |
| protected void serializeClassMappingContent(ClassMetaData mapping) |
| throws SAXException { |
| ClassMapping cls = (ClassMapping) mapping; |
| ClassMappingInfo info = cls.getMappingInfo(); |
| serializeTable(info.getTableName(), "table", ClassUtil.getClassName(mapping.getDescribedType()), null, |
| info.getUniques(info.getTableName())); |
| for (String second : info.getSecondaryTableNames()) |
| serializeTable(second, "secondary-table", null, info, |
| info.getUniques(second)); |
| serializeColumns(info, ColType.PK_JOIN, null); |
| } |
| |
| @Override |
| protected void serializeInheritanceContent(ClassMetaData mapping) |
| throws SAXException { |
| ClassMapping cls = (ClassMapping) mapping; |
| ClassMappingInfo info = cls.getMappingInfo(); |
| DiscriminatorMappingInfo dinfo = cls.getDiscriminator() |
| .getMappingInfo(); |
| String strat = info.getHierarchyStrategy(); |
| if (FlatClassStrategy.ALIAS.equals(strat)) |
| addAttribute("strategy", "SINGLE_TABLE"); |
| else if (VerticalClassStrategy.ALIAS.equals(strat)) |
| addAttribute("strategy", "JOINED"); |
| else if (FullClassStrategy.ALIAS.equals(strat)) |
| addAttribute("strategy", "TABLE_PER_CLASS"); |
| if (strat != null) { |
| startElement("inheritance"); |
| endElement("inheritance"); |
| } |
| if (dinfo.getValue() != null) { |
| startElement("discriminator-value"); |
| addText(dinfo.getValue()); |
| endElement("discriminator-value"); |
| } |
| serializeColumns(dinfo, ColType.DISC, null); |
| } |
| |
| /** |
| * Serialize table optionally listing primary-key-joins stored |
| * in the given {@link ClassMappingInfo}. |
| */ |
| private void serializeTable(String table, String elementName, |
| String defaultName, ClassMappingInfo secondaryInfo, Unique[] uniques) |
| throws SAXException { |
| List<Column> cols = null; |
| if (secondaryInfo != null) |
| cols = (List<Column>) 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) |
| addAttribute("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()) |
| { |
| addAttribute("schema", table.substring(0, index)); |
| } |
| addAttribute("name", table.substring(index + 1)); |
| } |
| } |
| if (print) { |
| startElement(elementName); |
| if (cols != null) { |
| for (Column col : cols) |
| serializeColumn(col, ColType.PK_JOIN, null, false); |
| } |
| if (uniques != null) |
| for (Unique unique: uniques) |
| serializeUniqueConstraint(unique); |
| endElement(elementName); |
| } |
| } |
| |
| @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 = (List<Column>) info.getColumns(); |
| if (cols == null || cols.size() == 0) |
| return false; |
| ValueMappingInfo info2 = field2.getValueInfo(); |
| List<Column> cols2 = (List<Column>) 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) |
| throws SAXException { |
| FieldMapping fm = (FieldMapping) fmd; |
| serializeColumns(fm.getValueInfo(), ColType.COL, fm.getMappingInfo() |
| .getTableName()); |
| } |
| |
| @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) |
| throws SAXException { |
| 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()); |
| return; |
| case ONE_MANY: |
| if (field.getMappingInfo().getJoinDirection() == |
| MappingInfo.JOIN_NONE) { |
| serializeColumns(field.getElementMapping().getValueInfo(), |
| ColType.JOIN, null); |
| return; |
| } |
| // else no break |
| case MANY_MANY: |
| if (field.getMappingInfo().hasSchemaComponents() |
| || field.getElementMapping().getValueInfo() |
| .hasSchemaComponents()) { |
| String table = field.getMappingInfo().getTableName(); |
| if (table != null) { |
| int index = table.indexOf('.'); |
| if (index < 0) |
| addAttribute("name", table); |
| else { |
| addAttribute("schema", table.substring(0, index)); |
| addAttribute("name", table.substring(index + 1)); |
| } |
| } |
| startElement("join-table"); |
| serializeColumns(field.getMappingInfo(), ColType.JOIN, |
| null); |
| serializeColumns(field.getElementMapping().getValueInfo(), |
| ColType.INVERSE, null); |
| endElement("join-table"); |
| } |
| return; |
| case ELEM_COLL: |
| if (field.getMappingInfo().hasSchemaComponents() |
| || field.getElementMapping().getValueInfo() |
| .hasSchemaComponents()) { |
| String table = field.getMappingInfo().getTableName(); |
| if (table != null) { |
| int index = table.indexOf('.'); |
| if (index < 0) |
| addAttribute("name", table); |
| else { |
| addAttribute("schema", table.substring(0, index)); |
| addAttribute("name", table.substring(index + 1)); |
| } |
| } |
| startElement("collection-table"); |
| ValueMappingImpl elem = |
| (ValueMappingImpl) field.getElement(); |
| serializeColumns(elem.getValueInfo(), ColType.COL, |
| null); |
| endElement("collection-table"); |
| } |
| return; |
| } |
| |
| serializeColumns(field.getValueInfo(), ColType.COL, |
| field.getMappingInfo().getTableName()); |
| if (strategy == PersistenceStrategy.BASIC && isLob(field)) { |
| startElement("lob"); |
| endElement("lob"); |
| } |
| TemporalType temporal = getTemporal(field); |
| if (temporal != null) { |
| startElement("temporal"); |
| addText(temporal.toString()); |
| endElement("temporal"); |
| } |
| |
| EnumType enumType = getEnumType(field); |
| if (enumType != null && enumType != EnumType.ORDINAL) { |
| startElement("enumerated"); |
| addText(enumType.toString()); |
| endElement("enumerated"); |
| } |
| } |
| |
| /** |
| * Serialize order column. |
| */ |
| @Override |
| protected void serializeOrderColumn(FieldMetaData fmd) |
| throws SAXException { |
| FieldMapping field = (FieldMapping) fmd; |
| Column orderCol = field.getOrderColumn(); |
| if (orderCol != null) { |
| if (orderCol.getName() != null) |
| addAttribute("name", orderCol.getName()); |
| if (orderCol.isNotNull()) |
| addAttribute("nullable", "false"); |
| if (orderCol.getFlag(Column.FLAG_UNINSERTABLE)) |
| addAttribute("insertable", "false"); |
| if (orderCol.getFlag(Column.FLAG_UNUPDATABLE)) |
| addAttribute("updatable", "false"); |
| if (orderCol.getTypeName() != null) |
| addAttribute("column-definition", orderCol.getTypeName()); |
| startElement("order-column"); |
| endElement("order-column"); |
| } |
| } |
| |
| /** |
| * Determine if the field is a lob. |
| */ |
| private boolean isLob(FieldMapping field) { |
| for (Column col : (List<Column>) 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 : (List<Column>) 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) |
| 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) |
| throws SAXException { |
| List<Column> cols = (List<Column>) info.getColumns(); |
| if (cols == null) |
| return; |
| for (Column col : cols) |
| serializeColumn(col, type, secondary, info.getUnique() != null); |
| } |
| |
| /** |
| * Serialize a single column. |
| */ |
| private void serializeColumn(Column col, ColType type, String secondary, |
| boolean unique) |
| throws SAXException { |
| if (col.getName() != null) |
| addAttribute("name", col.getName()); |
| if (col.getTypeName() != null) |
| addAttribute("column-definition", col.getTypeName()); |
| if (col.getTarget() != null |
| && (type == ColType.JOIN || type == ColType.INVERSE |
| || type == ColType.PK_JOIN)) |
| addAttribute("referenced-column-name", col.getTarget()); |
| if (type == ColType.COL || type == ColType.JOIN |
| || type == ColType.PK_JOIN) { |
| if (unique) |
| addAttribute("unique", "true"); |
| if (col.isNotNull()) |
| addAttribute("nullable", "false"); |
| if (col.getFlag(Column.FLAG_UNINSERTABLE)) |
| addAttribute("insertable", "false"); |
| if (col.getFlag(Column.FLAG_UNUPDATABLE)) |
| addAttribute("updatable", "false"); |
| if (secondary != null) |
| addAttribute("table", secondary); |
| |
| if (type == ColType.COL) { |
| if (col.getSize() > 0 && col.getSize() != 255) |
| addAttribute("length", col.getSize() + ""); |
| if (col.getDecimalDigits() != 0) |
| addAttribute("scale", col.getDecimalDigits() + ""); |
| } |
| } |
| if (type != ColType.COL || getAttributes().getLength() > 0) { |
| String name = col.getFlag(Column.FLAG_PK_JOIN) ? _names |
| .get(ColType.PK_JOIN) : _names.get(type); |
| startElement(name); |
| endElement(name); |
| } |
| } |
| |
| private void serializeUniqueConstraint(Unique unique) throws SAXException { |
| if (StringUtil.isNotEmpty(unique.getName())) { |
| addAttribute("name", unique.getName()); |
| } |
| startElement("unique-constraint"); |
| Column[] columns = unique.getColumns(); |
| for (Column column:columns) { |
| startElement("column-name"); |
| addText(column.getName()); |
| endElement("column-name"); |
| } |
| endElement("unique-constraint"); |
| } |
| |
| @Override |
| protected SerializationComparator newSerializationComparator() { |
| return new 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 (List<QueryResultMapping>) 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) |
| throws SAXException { |
| if (obj instanceof QueryResultMapping) |
| serializeQueryResultMapping((QueryResultMapping) obj); |
| } |
| |
| @Override |
| protected void serializeQueryMappings(ClassMetaData meta) |
| throws SAXException { |
| for (QueryResultMapping res : getQueryResultMappings(meta)) |
| serializeQueryResultMapping(res); |
| } |
| |
| /** |
| * Serialize given result set mapping. |
| */ |
| private void serializeQueryResultMapping(QueryResultMapping meta) |
| throws SAXException { |
| if (!getSerializeAnnotations() |
| && meta.getSourceType() == SourceTracker.SRC_ANNOTATIONS) |
| return; |
| |
| addAttribute("name", meta.getName()); |
| startElement("sql-result-set-mapping"); |
| for (QueryResultMapping.PCResult pc : meta.getPCResults()) { |
| addAttribute("entity-class", pc.getCandidateType().getName()); |
| Object discrim = pc.getMapping(PCResult.DISCRIMINATOR); |
| if (discrim != null) |
| addAttribute("discriminator-column", discrim.toString()); |
| |
| startElement("entity-result"); |
| for (String path : pc.getMappingPaths()) { |
| addAttribute("name", path); |
| addAttribute("column", pc.getMapping(path).toString()); |
| startElement("field-result"); |
| endElement("field-result"); |
| } |
| endElement("entity-result"); |
| } |
| for (Object col : meta.getColumnResults()) { |
| addAttribute("name", col.toString()); |
| startElement("column-result"); |
| endElement("column-result"); |
| } |
| endElement("sql-result-set-mapping"); |
| } |
| |
| @Override |
| protected void serializeSequence(SequenceMetaData meta) |
| throws SAXException { |
| if (!getSerializeAnnotations() |
| && meta.getSourceType() == SourceTracker.SRC_ANNOTATIONS) |
| return; |
| if (SequenceMapping.IMPL_VALUE_TABLE.equals(meta.getSequencePlugin())) { |
| super.serializeSequence(meta); |
| return; |
| } |
| |
| SequenceMapping seq = (SequenceMapping) meta; |
| addAttribute("name", seq.getName()); |
| String table = seq.getTable(); |
| if (table != null) { |
| int dotIdx = table.indexOf('.'); |
| if (dotIdx == -1) |
| addAttribute("table", table); |
| else { |
| addAttribute("table", table.substring(dotIdx + 1)); |
| addAttribute("schema", table.substring(0, dotIdx)); |
| } |
| } |
| if (!StringUtil.isEmpty(seq.getPrimaryKeyColumn())) |
| addAttribute("pk-column-name", seq.getPrimaryKeyColumn()); |
| if (!StringUtil.isEmpty(seq.getSequenceColumn())) |
| addAttribute("value-column-name", seq.getSequenceColumn()); |
| if (!StringUtil.isEmpty(seq.getPrimaryKeyValue())) |
| addAttribute("pk-column-value", seq.getPrimaryKeyValue()); |
| if (seq.getAllocate() != 50 && seq.getAllocate() != -1) |
| addAttribute("allocation-size", seq.getAllocate() + ""); |
| if (seq.getInitialValue() != 0 && seq.getInitialValue() != -1) |
| addAttribute("initial-value", seq.getInitialValue() + ""); |
| startElement("table-generator"); |
| endElement("table-generator"); |
| } |
| |
| /** |
| * Column types serialized under different names. |
| */ |
| private static enum ColType { |
| |
| COL, |
| JOIN, |
| INVERSE, |
| PK_JOIN, |
| DISC |
| } |
| |
| /** |
| * 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 ()); |
| } |
| } |
| } |