You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by mp...@apache.org on 2007/07/01 21:37:05 UTC

svn commit: r552358 [2/2] - in /openjpa/trunk: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ant/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/meta/ openjpa-kernel/src/main/java/o...

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataSerializer.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataSerializer.java?view=auto&rev=552358
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataSerializer.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataSerializer.java Sun Jul  1 12:37:04 2007
@@ -0,0 +1,1488 @@
+/*
+ * 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;
+
+import org.apache.openjpa.lib.meta.SourceTracker;
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.lib.util.JavaVersions;
+import org.apache.openjpa.lib.log.Log;
+import org.apache.openjpa.lib.conf.Configurations;
+import org.apache.openjpa.conf.OpenJPAConfiguration;
+import org.apache.openjpa.meta.*;
+import org.apache.openjpa.kernel.QueryLanguages;
+import org.apache.openjpa.util.InternalException;
+import org.apache.commons.lang.StringUtils;
+
+import java.util.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.Writer;
+import java.io.FileWriter;
+import java.lang.reflect.Member;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.annotation.Annotation;
+
+import serp.util.Strings;
+
+import javax.persistence.Entity;
+import javax.persistence.Embeddable;
+import javax.persistence.MappedSuperclass;
+import javax.persistence.NamedNativeQuery;
+import javax.persistence.NamedQuery;
+import javax.persistence.QueryHint;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Version;
+import javax.persistence.Transient;
+import javax.persistence.Basic;
+import javax.persistence.Embedded;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.ManyToMany;
+import javax.persistence.OrderBy;
+import javax.persistence.MapKey;
+import javax.persistence.AttributeOverride;
+import javax.persistence.CascadeType;
+import javax.persistence.FetchType;
+
+//@todo: javadocs
+
+/**
+ * Serializes persistence metadata as annotations.
+ * This class processes all object level tags that are store-agnostic.
+ * However, it provides hooks for the subclasses to include store-specific
+ * tags to be serialized both at <entity-mappings> and
+ * <entity> level.
+ *
+ * @since 1.0.0
+ * @author Steve Kim
+ * @author Gokhan Ergul
+ * @nojavadoc
+ */
+public class AnnotationPersistenceMetaDataSerializer
+    implements PersistenceMetaDataFactory.Serializer {
+
+    // NOTE: order is important! these constants must be maintained in
+    // serialization order. constants are spaced so that subclasses can
+    // slip tags in-between
+    protected static final int TYPE_SEQ = 10;
+    protected static final int TYPE_QUERY = 20;
+    protected static final int TYPE_META = 30;
+    protected static final int TYPE_CLASS_SEQS = 40;
+    protected static final int TYPE_CLASS_QUERIES = 50;
+
+    private static final Localizer _loc = Localizer.forPackage
+        (AnnotationPersistenceMetaDataSerializer.class);
+
+    private Log _log = null;
+    
+    private final OpenJPAConfiguration _conf;
+    private Map<String, ClassMetaData> _metas = null;
+    private Map<String, List> _queries = null;
+    private Map<String, List> _seqs = null;
+    private int _mode = MetaDataModes.MODE_NONE;
+    private SerializationComparator _comp = null;
+
+    private Map<ClassMetaData, List<AnnotationBuilder>> _clsAnnos = null;
+    private Map<FieldMetaData, List<AnnotationBuilder>> _fldAnnos = null;
+    private Map<SequenceMetaData, List<AnnotationBuilder>> _seqAnnos = null;
+    private Map<QueryMetaData, List<AnnotationBuilder>> _qryAnnos = null; 
+
+    /**
+     * Constructor. Supply configuration.
+     */
+    public AnnotationPersistenceMetaDataSerializer(OpenJPAConfiguration conf) {
+        _conf = conf;
+        setLog(conf.getLog(OpenJPAConfiguration.LOG_METADATA));
+        setMode(MetaDataModes.MODE_META | MetaDataModes.MODE_MAPPING |
+            MetaDataModes.MODE_QUERY);
+    }
+
+    /**
+     * Configuration.
+     */
+    public OpenJPAConfiguration getConfiguration() {
+        return _conf;
+    }
+
+    /**
+     * The log to write to.
+     */
+    public Log getLog() {
+        return _log;
+    }
+
+    /**
+     * The log to write to.
+     */
+    public void setLog(Log log) {
+        _log = log;
+    }
+    
+    /**
+     * The serialization mode according to the expected document type. The
+     * mode constants act as bit flags, and therefore can be combined.
+     */
+    public int getMode() {
+        return _mode;
+    }
+
+    /**
+     * The serialization mode according to the expected document type. The
+     * mode constants act as bit flags, and therefore can be combined.
+     */
+    public void setMode(int mode) {
+        _mode = mode;
+    }
+
+    /**
+     * The serialization mode according to the expected document type.
+     */
+    public void setMode(int mode, boolean on) {
+        if (mode == MetaDataModes.MODE_NONE)
+            setMode(MetaDataModes.MODE_NONE);
+        else if (on)
+            setMode(_mode | mode);
+        else
+            setMode(_mode & ~mode);
+    }
+
+    /**
+     * Convenience method for interpreting {@link #getMode}.
+     */
+    protected boolean isMetaDataMode() {
+        return (_mode & MetaDataModes.MODE_META) != 0;
+    }
+
+    /**
+     * Convenience method for interpreting {@link #getMode}.
+     */
+    protected boolean isQueryMode() {
+        return (_mode & MetaDataModes.MODE_QUERY) != 0;
+    }
+
+    /**
+     * Convenience method for interpreting {@link #getMode}.
+     */
+    protected boolean isMappingMode() {
+        return (_mode & MetaDataModes.MODE_MAPPING) != 0;
+    }
+
+    /**
+     * Convenience method for interpreting {@link #getMode}. Takes into
+     * account whether mapping information is loaded for the given instance.
+     */
+    protected boolean isMappingMode(ClassMetaData meta) {
+        return isMappingMode() && (meta.getSourceMode()
+            & MetaDataModes.MODE_MAPPING) != 0
+            && (meta.getEmbeddingMetaData() != null
+            || !meta.isEmbeddedOnly())
+            && (meta.getEmbeddingMetaData() == null
+            || isMappingMode(meta.getEmbeddingMetaData()));
+    }
+
+    /**
+     * Convenience method for interpreting {@link #getMode}. Takes into
+     * account whether mapping information is loaded for the given instance.
+     */
+    protected boolean isMappingMode(ValueMetaData vmd) {
+        return isMappingMode(vmd.getFieldMetaData().getDefiningMetaData());
+    }
+
+    /**
+     * Add a class meta data to the set to be serialized.
+     */
+    public void addMetaData(ClassMetaData meta) {
+        if (meta == null)
+            return;
+
+        if (_metas == null)
+            _metas = new HashMap<String, ClassMetaData>();
+        _metas.put(meta.getDescribedType().getName(), meta);
+    }
+
+    /**
+     * Add a sequence meta data to the set to be serialized.
+     */
+    public void addSequenceMetaData(SequenceMetaData meta) {
+        if (meta == null)
+            return;
+
+        List seqs = null;
+        String defName = null;
+        if (meta.getSourceScope() instanceof Class)
+            defName = ((Class) meta.getSourceScope()).getName();
+        if (_seqs == null)
+            _seqs = new HashMap<String, List>();
+        else
+            seqs = _seqs.get(defName);
+
+        if (seqs == null) {
+            seqs = new ArrayList(3); // don't expect many seqs / class
+            seqs.add(meta);
+            _seqs.put(defName, seqs);
+        } else if (!seqs.contains(meta))
+            seqs.add(meta);
+    }
+
+    /**
+     * Add a query meta data to the set to be serialized.
+     */
+    public void addQueryMetaData(QueryMetaData meta) {
+        if (meta == null)
+            return;
+
+        List queries = null;
+        String defName = null;
+        if (meta.getSourceScope() instanceof Class)
+            defName = ((Class) meta.getSourceScope()).getName();
+        if (_queries == null)
+            _queries = new HashMap<String, List>();
+        else
+            queries = _queries.get(defName);
+
+        if (queries == null) {
+            queries = new ArrayList(3); // don't expect many queries / class
+            queries.add(meta);
+            _queries.put(defName, queries);
+        } else if (!queries.contains(meta))
+            queries.add(meta);
+    }
+
+    /**
+     * Add all components in the given repository to the set to be serialized.
+     */
+    public void addAll(MetaDataRepository repos) {
+        if (repos == null)
+            return;
+
+        for (ClassMetaData meta : repos.getMetaDatas())
+            addMetaData(meta);
+        for (SequenceMetaData seq : repos.getSequenceMetaDatas())
+            addSequenceMetaData(seq);
+        for (QueryMetaData query : repos.getQueryMetaDatas())
+            addQueryMetaData(query);
+    }
+
+    /**
+     * Remove a metadata from the set to be serialized.
+     *
+     * @return true if removed, false if not in set
+     */
+    public boolean removeMetaData(ClassMetaData meta) {
+        return _metas != null && meta != null
+            && _metas.remove(meta.getDescribedType().getName()) != null;
+    }
+
+    /**
+     * Remove a sequence metadata from the set to be serialized.
+     *
+     * @return true if removed, false if not in set
+     */
+    public boolean removeSequenceMetaData(SequenceMetaData meta) {
+        if (_seqs == null || meta == null)
+            return false;
+        String defName = null;
+        if (meta.getSourceScope() instanceof Class)
+            defName = ((Class) meta.getSourceScope()).getName();
+        List seqs = _seqs.get(defName);
+        if (seqs == null)
+            return false;
+        if (!seqs.remove(meta))
+            return false;
+        if (seqs.isEmpty())
+            _seqs.remove(defName);
+        return true;
+    }
+
+    /**
+     * Remove a query metadata from the set to be serialized.
+     *
+     * @return true if removed, false if not in set
+     */
+    public boolean removeQueryMetaData(QueryMetaData meta) {
+        if (_queries == null || meta == null)
+            return false;
+        String defName = null;
+        if (meta.getSourceScope() instanceof Class)
+            defName = ((Class) meta.getSourceScope()).getName();
+        List queries = _queries.get(defName);
+        if (queries == null)
+            return false;
+        if (!queries.remove(meta))
+            return false;
+        if (queries.isEmpty())
+            _queries.remove(defName);
+        return true;
+    }
+
+    /**
+     * Remove all the components in the given repository from the set to be
+     * serialized.
+     *
+     * @return true if any components removed, false if none in set
+     */
+    public boolean removeAll(MetaDataRepository repos) {
+        if (repos == null)
+            return false;
+
+        boolean removed = false;
+        ClassMetaData[] metas = repos.getMetaDatas();
+        for (int i = 0; i < metas.length; i++)
+            removed |= removeMetaData(metas[i]);
+        SequenceMetaData[] seqs = repos.getSequenceMetaDatas();
+        for (int i = 0; i < seqs.length; i++)
+            removed |= removeSequenceMetaData(seqs[i]);
+        QueryMetaData[] queries = repos.getQueryMetaDatas();
+        for (int i = 0; i < queries.length; i++)
+            removed |= removeQueryMetaData(queries[i]);
+        return removed;
+    }
+
+    /**
+     * Clear the set of metadatas to be serialized.
+     */
+    public void clear() {
+        if (_metas != null)
+            _metas.clear();
+        if (_seqs != null)
+            _seqs.clear();
+        if (_queries != null)
+            _queries.clear();
+    }
+
+    /**
+     * Add system-level mapping elements to be serialized. Does nothing
+     * by default.
+     */
+    protected void addSystemMappingElements(Collection toSerialize) {
+    }
+
+    /**
+     * Sort the given collection of objects to be serialized.
+     */
+    private void serializationSort(List objs) {
+        if (objs == null || objs.isEmpty())
+            return;
+        if (_comp == null)
+            _comp = newSerializationComparator();
+        Collections.sort(objs, _comp);
+    }
+
+    /**
+     * Create a new comparator for ordering objects that are to be serialized.
+     */
+    protected SerializationComparator newSerializationComparator() {
+        return _comp;
+    }
+
+    /**
+     * Add sequence metadata to the given metadatas collection.
+     */
+    private void addSequenceMetaDatas(Collection all) {
+        if (_seqs == null)
+            return;
+
+        for (Map.Entry entry : _seqs.entrySet()) {
+            if (entry.getKey() == null)
+                all.addAll((List) entry.getValue());
+            else if (_metas == null || !_metas.containsKey(entry.getKey()))
+                all.add(new ClassSeqs((List<SequenceMetaData>)
+                    entry.getValue()));
+        }
+    }
+
+    /**
+     * Add query metadata to the given metadatas collection.
+     */
+    private void addQueryMetaDatas(Collection all) {
+        if (_queries == null)
+            return;
+
+        for (Map.Entry entry : _queries.entrySet()) {
+            if (entry.getKey() == null)
+                all.addAll((List) entry.getValue());
+            else if (_mode == MetaDataModes.MODE_QUERY || _metas == null
+                || !_metas.containsKey(entry.getKey()))
+                all.add(new ClassQueries((List<QueryMetaData>)
+                    entry.getValue()));
+        }
+    }
+
+    /**
+     * Creates a new annotation builder for the specified annotation type.
+     * @return
+     */
+    protected AnnotationBuilder newAnnotationBuilder(
+        Class<? extends Annotation> annType) {
+        return new AnnotationBuilder(annType);        
+    }
+
+    protected void addAnnotation(AnnotationBuilder ab, Object meta) {
+        if (meta instanceof ClassMetaData)
+            addAnnotation(ab, (ClassMetaData) meta);
+        else if (meta instanceof FieldMetaData)
+            addAnnotation(ab, (FieldMetaData) meta);
+        else if (meta instanceof SequenceMetaData)
+            addAnnotation(ab, (SequenceMetaData) meta);
+        else if (meta instanceof QueryMetaData)
+            addAnnotation(ab, (QueryMetaData) meta);
+    }
+
+    /**
+     * Add an annotation builder to list of builders for the specified
+     * class metadata.
+     */
+    protected void addAnnotation(AnnotationBuilder ab, ClassMetaData meta) {
+        if (_clsAnnos == null)
+            _clsAnnos = new HashMap<ClassMetaData, List<AnnotationBuilder>>();
+        List<AnnotationBuilder> list = _clsAnnos.get(meta);
+        if (list == null) {
+            list = new ArrayList<AnnotationBuilder>();
+            _clsAnnos.put(meta, list);
+        }
+        list.add(ab);        
+    }
+
+    /**
+     * Add an annotation builder to list of builders for the specified
+     * field metadata.
+     */
+    protected void addAnnotation(AnnotationBuilder ab, FieldMetaData meta) {
+        if (_fldAnnos == null)
+            _fldAnnos = new HashMap<FieldMetaData, List<AnnotationBuilder>>();
+        List<AnnotationBuilder> list = _fldAnnos.get(meta);
+        if (list == null) {
+            list = new ArrayList<AnnotationBuilder>();
+            _fldAnnos.put(meta, list);
+        }
+        list.add(ab);
+    }
+
+    /**
+     * Add an annotation builder to list of builders for the specified
+     * sequence metadata.
+     */
+    protected void addAnnotation(AnnotationBuilder ab, SequenceMetaData meta) {
+        if (_seqAnnos == null)
+            _seqAnnos = new HashMap<SequenceMetaData, List<AnnotationBuilder>>();
+        List<AnnotationBuilder> list = _seqAnnos.get(meta);
+        if (list == null) {
+            list = new ArrayList<AnnotationBuilder>();
+            _seqAnnos.put(meta, list);
+        }
+        list.add(ab);
+    }
+
+    /**
+     * Add an annotation builder to list of builders for the specified
+     * query metadata.
+     */
+    protected void addAnnotation(AnnotationBuilder ab, QueryMetaData meta) {
+        if (_qryAnnos == null)
+            _qryAnnos = new HashMap<QueryMetaData, List<AnnotationBuilder>>();
+        List<AnnotationBuilder> list = _qryAnnos.get(meta);
+        if (list == null) {
+            list = new ArrayList<AnnotationBuilder>();
+            _qryAnnos.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, ClassMetaData meta) {
+        AnnotationBuilder ab = newAnnotationBuilder(annType);
+        if (meta == null)
+            return ab;
+        addAnnotation(ab, meta);
+        return 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, FieldMetaData meta) {
+        AnnotationBuilder ab = newAnnotationBuilder(annType);
+        if (meta == null)
+            return ab;
+        addAnnotation(ab, meta);
+        return 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, SequenceMetaData meta) {
+        AnnotationBuilder ab = newAnnotationBuilder(annType);
+        if (meta == null)
+            return ab;
+        addAnnotation(ab, meta);
+        return 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, QueryMetaData meta) {
+        AnnotationBuilder ab = newAnnotationBuilder(annType);
+        if (meta == null)
+            return ab;
+        addAnnotation(ab, meta);
+        return ab;
+    }
+    
+    protected void serialize(Collection objects) {
+        for (Object obj : objects) {
+            int type = type(obj);
+            switch (type) {
+                case TYPE_META:
+                    serializeClass((ClassMetaData) obj);
+                    break;
+                case TYPE_SEQ:
+                    if (isMappingMode())
+                        serializeSequence((SequenceMetaData) obj);
+                case TYPE_QUERY:
+                    serializeQuery((QueryMetaData) obj);
+                    break;
+                case TYPE_CLASS_QUERIES:
+                    for (QueryMetaData query : ((ClassQueries) obj)
+                        .getQueries())
+                        serializeQuery(query);
+                    break;
+                case TYPE_CLASS_SEQS:
+                    if (isMappingMode())
+                        for (SequenceMetaData seq : ((ClassSeqs) obj)
+                            .getSequences())
+                            serializeSequence(seq);
+                    break;
+                default:
+                    if (isMappingMode())
+                        serializeSystemMappingElement(obj);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Return the type constant for the given object based on its runtime
+     * class. If the runtime class does not correspond to any of the known
+     * types then returns -1. This can happen for tags
+     * that are not handled at this store-agnostic level.
+     */
+    protected int type(Object o) {
+        if (o instanceof ClassMetaData)
+            return TYPE_META;
+        if (o instanceof QueryMetaData)
+            return TYPE_QUERY;
+        if (o instanceof SequenceMetaData)
+            return TYPE_SEQ;
+        if (o instanceof ClassQueries)
+            return TYPE_CLASS_QUERIES;
+        if (o instanceof ClassSeqs)
+            return TYPE_CLASS_SEQS;
+        return -1;
+    }
+
+    /**
+     * Serialize unknown mapping element at system level.
+     */
+    protected void serializeSystemMappingElement(Object obj) {
+    }
+
+    /**
+     * Serialize query metadata.
+     */
+    private void serializeQuery(QueryMetaData meta) {
+        Log log = getLog();
+        if (log.isInfoEnabled()) {
+            if (meta.getSourceScope() instanceof Class)
+                log.info(_loc.get("ser-cls-query",
+                    meta.getSourceScope(), meta.getName()));
+            else
+                log.info(_loc.get("ser-query", meta.getName()));
+        }
+
+        Class<? extends Annotation> ann =
+            QueryLanguages.LANG_SQL.equals(meta.getLanguage()) ?
+            NamedNativeQuery.class : NamedQuery.class;
+        AnnotationBuilder abQry = addAnnotation(ann, meta);
+        abQry.add("name", meta.getName());
+        abQry.add("query", meta.getQueryString());
+        if (QueryLanguages.LANG_SQL.equals(meta.getLanguage())) {
+            if (meta.getResultType() != null)
+                abQry.add("resultClass", meta.getResultType());
+        }
+        serializeQueryHints(meta, abQry);
+    }
+
+    /**
+     * Serialize query hints.
+     */
+    private void serializeQueryHints(QueryMetaData meta, AnnotationBuilder ab) {
+        String[] hints = meta.getHintKeys();
+        Object[] values = meta.getHintValues();
+        for (int i = 0; i < hints.length; i++) {
+            AnnotationBuilder abHint = newAnnotationBuilder(QueryHint.class);
+            abHint.add("name", hints[i]);
+            abHint.add("value", String.valueOf(values[i]));
+            ab.add("hints", abHint);
+        }
+    }
+
+    /**
+     * Serialize sequence metadata.
+     */
+    protected void serializeSequence(SequenceMetaData meta) {
+        Log log = getLog();
+        if (log.isInfoEnabled())
+            log.info(_loc.get("ser-sequence", meta.getName()));
+
+        AnnotationBuilder ab = addAnnotation(SequenceGenerator.class, meta);
+        ab.add("name", meta.getName());
+
+        // parse out the datastore sequence name, if any
+        String plugin = meta.getSequencePlugin();
+        String clsName = Configurations.getClassName(plugin);
+        String props = Configurations.getProperties(plugin);
+        String ds = null;
+        if (props != null) {
+            Properties map = Configurations.parseProperties(props);
+            ds = (String) map.remove("Sequence");
+            if (ds != null) {
+                props = Configurations.serializeProperties(map);
+                plugin = Configurations.getPlugin(clsName, props);
+            }
+        }
+
+        if (ds != null)
+            ab.add("sequenceName", ds);
+        else if (plugin != null && !SequenceMetaData.IMPL_NATIVE.equals
+            (plugin))
+            ab.add("sequenceName", plugin);
+        if (meta.getInitialValue() != 0 && meta.getInitialValue() != -1)
+            ab.add("initialValue", meta.getInitialValue());
+        if (meta.getAllocate() != 50 && meta.getAllocate() != -1)
+            ab.add("allocationSize", meta.getAllocate());
+    }
+
+    /**
+     * Serialize class metadata.
+     */
+    protected void serializeClass(ClassMetaData meta) {
+        Log log = getLog();
+        if (log.isInfoEnabled())
+            log.info(_loc.get("ser-class", meta));
+
+        AnnotationBuilder abEntity = addAnnotation(
+            getEntityAnnotationType(meta), meta);
+        if (isMetaDataMode()
+            && !meta.getTypeAlias().equals(Strings.getClassName(meta.
+            getDescribedType())))
+            abEntity.add("name", meta.getTypeAlias());
+        
+        if (isMappingMode())
+            addClassMappingAnnotations(meta);
+
+        if (isMappingMode())
+            serializeClassMappingContent(meta);
+        if (isMetaDataMode())
+            serializeIdClass(meta);
+        if (isMappingMode())
+            serializeInheritanceContent(meta);
+
+        if (isMappingMode()) {
+            List seqs = (_seqs == null) ? null : _seqs.get
+                (meta.getDescribedType().getName());
+            if (seqs != null) {
+                serializationSort(seqs);
+                for (int i = 0; i < seqs.size(); i++)
+                    serializeSequence((SequenceMetaData) seqs.get(i));
+            }
+        }
+
+        if (isQueryMode()) {
+            List queries = (_queries == null) ? null : _queries.get
+                (meta.getDescribedType().getName());
+            if (queries != null) {
+                serializationSort(queries);
+                for (int i = 0; i < queries.size(); i++)
+                    serializeQuery((QueryMetaData) queries.get(i));
+            }
+            if (isMappingMode())
+                serializeQueryMappings(meta);
+        }
+
+        List<FieldMetaData> fields = new ArrayList(Arrays.asList
+            (meta.getDefinedFieldsInListingOrder()));
+        Collections.sort(fields, new FieldComparator());
+
+        // serialize attr-override
+        if (isMappingMode()) {
+            FieldMetaData fmd;
+            FieldMetaData orig;
+            for (Iterator<FieldMetaData> it = fields.iterator(); it.hasNext();)
+            {
+                fmd = it.next();
+                if (meta.getDefinedSuperclassField(fmd.getName()) == null)
+                    continue;
+                orig = meta.getPCSuperclassMetaData().getField(fmd.getName());
+                if (serializeAttributeOverride(fmd, orig))
+                    serializeAttributeOverrideContent(fmd, orig);
+                it.remove();
+            }
+        }
+
+        if (fields.size() > 0 && (isMetaDataMode() || isMappingMode())) {
+            FieldMetaData orig;
+            for (FieldMetaData fmd : fields) {
+                if (fmd.getDeclaringType() != fmd.getDefiningMetaData().
+                    getDescribedType()) {
+                    orig = fmd.getDeclaringMetaData().getDeclaredField
+                        (fmd.getName());
+                } else
+                    orig = null;
+                serializeField(fmd, orig);
+            }
+        }
+    }
+
+    /**
+     * Return entity annotation type.
+     */
+    private static Class<? extends Annotation> getEntityAnnotationType(
+        ClassMetaData meta) {
+        switch (getEntityTag(meta)) {
+            case ENTITY:
+                return Entity.class;
+            case EMBEDDABLE:
+                return Embeddable.class;
+            case MAPPED_SUPERCLASS:
+                return MappedSuperclass.class;
+            default:
+                throw new IllegalStateException();
+        }
+    }
+
+    /**
+     * Return field annotation type.
+     */
+    private static Class<? extends Annotation> getFieldAnnotationType (
+        FieldMetaData fmd, PersistenceStrategy strat) {
+        Class<? extends Annotation> ann = null;
+        if (fmd.isPrimaryKey() && strat == PersistenceStrategy.EMBEDDED)
+            ann = EmbeddedId.class;
+        else if (fmd.isPrimaryKey())
+            ann = Id.class;
+        else if (fmd.isVersion())
+            ann = Version.class;
+        else {
+            switch (strat) {
+                case TRANSIENT:
+                    ann = Transient.class;
+                    break;
+                case BASIC:
+                    ann = Basic.class;
+                    break;
+                case EMBEDDED:
+                    ann = Embedded.class;
+                    break;
+                case MANY_ONE:
+                    ann = ManyToOne.class;
+                    break;
+                case ONE_ONE:
+                    ann = OneToOne.class;
+                    break;
+                case ONE_MANY:
+                    ann = OneToMany.class;
+                    break;
+                case MANY_MANY:
+                    ann = ManyToMany.class;
+                    break;
+            }
+        }
+        return ann;
+    }
+
+    /**
+     * Return the MetaDataTag for the given class meta data.
+     */
+    private static MetaDataTag getEntityTag(ClassMetaData meta) {
+        // @Embeddable classes can't declare Id fields
+        if (meta.isEmbeddedOnly() && meta.getPrimaryKeyFields().length == 0)
+            return MetaDataTag.EMBEDDABLE;
+        if (meta.isMapped())
+            return MetaDataTag.ENTITY;
+        return MetaDataTag.MAPPED_SUPERCLASS;
+    }
+
+    /**
+     * Add mapping attributes for the given class. Does nothing by default
+     */
+    protected void addClassMappingAnnotations(ClassMetaData mapping) {
+    }
+
+    /**
+     * Serialize id-class.
+     */
+    private void serializeIdClass(ClassMetaData meta) {
+        if (meta.getIdentityType() != ClassMetaData.ID_APPLICATION
+            || meta.isOpenJPAIdentity())
+            return;
+
+        ClassMetaData sup = meta.getPCSuperclassMetaData();
+        Class oid = meta.getObjectIdType();
+        if (oid != null && (sup == null || oid != sup.getObjectIdType())) {
+            AnnotationBuilder ab = addAnnotation(IdClass.class, meta);
+            ab.add(null, oid);
+        }
+    }
+
+    /**
+     * Serialize class mapping content. Does nothing by default.
+     */
+    protected void serializeClassMappingContent(ClassMetaData mapping) {
+    }
+
+    /**
+     * Serialize inheritance content. Does nothing by default.
+     */
+    protected void serializeInheritanceContent(ClassMetaData mapping) {
+    }
+
+    /**
+     * Serialize query mappings. Does nothing by default.
+     */
+    protected void serializeQueryMappings(ClassMetaData meta) {
+    }
+
+    /**
+     * Serialize the given field.
+     */
+    private void serializeField(FieldMetaData fmd, FieldMetaData orig) {
+        if (fmd.getManagement() != FieldMetaData.MANAGE_PERSISTENT
+            && !fmd.isExplicit())
+            return;
+
+        PersistenceStrategy strat = getStrategy(fmd);
+        ValueMetaData cascades = null;
+        AnnotationBuilder ab = addAnnotation(
+            getFieldAnnotationType (fmd, strat), fmd);        
+        if (fmd.isPrimaryKey() && strat == PersistenceStrategy.EMBEDDED)
+            ; // noop
+        else if (fmd.isPrimaryKey())
+            ; // noop
+        else if (fmd.isVersion())
+            ; // noop
+        else {
+            switch (strat) {
+                case BASIC:
+                    if (isMetaDataMode())
+                        addBasicAttributes(fmd, ab);
+                    break;
+                case MANY_ONE:
+                    if (isMetaDataMode())
+                        addManyToOneAttributes(fmd, ab);
+                    cascades = fmd;
+                    break;
+                case ONE_ONE:
+                    if (isMetaDataMode())
+                        addOneToOneAttributes(fmd, ab);
+                    cascades = fmd;
+                    break;
+                case ONE_MANY:
+                    if (isMetaDataMode())
+                        addOneToManyAttributes(fmd, ab);
+                    cascades = fmd.getElement();
+                    break;
+                case MANY_MANY:
+                    if (isMetaDataMode())
+                        addManyToManyAttributes(fmd, ab);
+                    cascades = fmd.getElement();
+                    break;
+            }
+            if (isMappingMode())
+                addStrategyMappingAttributes(fmd, ab);
+        }
+        if (isMappingMode(fmd))
+            addFieldMappingAttributes(fmd, orig, ab);
+
+        if (fmd.getOrderDeclaration() != null) {
+            if (!(Order.ELEMENT + " asc").equals(fmd.getOrderDeclaration()))
+                addAnnotation(OrderBy.class, fmd).
+                    add (null, fmd.getOrderDeclaration());
+        }
+        if (isMappingMode() && fmd.getKey().getValueMappedBy() != null) {
+            AnnotationBuilder abMapKey = addAnnotation(MapKey.class, fmd);
+            FieldMetaData mapBy = fmd.getKey().getValueMappedByMetaData();
+            if (!mapBy.isPrimaryKey() ||
+                mapBy.getDefiningMetaData().getPrimaryKeyFields().length != 1) {
+                abMapKey.add("name", fmd.getKey().getValueMappedBy());
+            }
+        }
+        if (isMappingMode(fmd))
+            serializeFieldMappingContent(fmd, strat, ab);
+        if (cascades != null && isMetaDataMode())
+            serializeCascades(cascades, ab);
+    }
+
+    /**
+     * Add mapping attributes for the given field. Does nothing by default.
+     */
+    protected void addFieldMappingAttributes(FieldMetaData fmd,
+        FieldMetaData orig, AnnotationBuilder ab) {
+    }
+    
+    /**
+     * Always returns false by default.
+     */
+    protected boolean serializeAttributeOverride(FieldMetaData fmd,
+        FieldMetaData orig) {
+        return false;
+    }
+
+    /**
+     * Serialize attribute override content.
+     */
+    private void serializeAttributeOverrideContent(FieldMetaData fmd,
+        FieldMetaData orig) {
+        AnnotationBuilder ab = addAnnotation(AttributeOverride.class, fmd);
+        ab.add("name", fmd.getName());
+        serializeAttributeOverrideMappingContent(fmd, orig, ab);
+    }
+
+    /**
+     * Serialize attribute override mapping content. Does nothing by default,
+     */
+    protected void serializeAttributeOverrideMappingContent
+        (FieldMetaData fmd, FieldMetaData orig, AnnotationBuilder ab) {
+    }
+
+
+    /**
+     * Serialize cascades.
+     */
+    private void serializeCascades(ValueMetaData vmd, AnnotationBuilder ab) {
+        EnumSet<CascadeType> cascades = EnumSet.noneOf(CascadeType.class);
+        if (vmd.getCascadePersist() == ValueMetaData.CASCADE_IMMEDIATE) {
+            cascades.add(CascadeType.PERSIST);
+        }
+        if (vmd.getCascadeAttach() == ValueMetaData.CASCADE_IMMEDIATE) {
+            cascades.add(CascadeType.MERGE);
+        }
+        if (vmd.getCascadeDelete() == ValueMetaData.CASCADE_IMMEDIATE) {
+            cascades.add(CascadeType.REMOVE);
+        }
+        if (vmd.getCascadeRefresh() == ValueMetaData.CASCADE_IMMEDIATE) {
+            cascades.add(CascadeType.REFRESH);
+        }
+        if (cascades.size() == 4) // ALL
+        {
+            cascades.clear();
+            cascades.add(CascadeType.ALL);
+        }
+        if (!cascades.isEmpty()) {
+            ab.add("cascade", cascades);
+        }
+    }
+
+    /**
+     * Return the serialized strategy name.
+     */
+    protected PersistenceStrategy getStrategy(FieldMetaData fmd) {
+        if (fmd.getManagement() == fmd.MANAGE_NONE)
+            return PersistenceStrategy.TRANSIENT;
+
+        if (fmd.isSerialized()
+            || fmd.getDeclaredType() == byte[].class
+            || fmd.getDeclaredType() == Byte[].class
+            || fmd.getDeclaredType() == char[].class
+            || fmd.getDeclaredType() == Character[].class)
+            return PersistenceStrategy.BASIC;
+
+        FieldMetaData mappedBy;
+        switch (fmd.getDeclaredTypeCode()) {
+            case JavaTypes.PC:
+                if (fmd.isEmbedded())
+                    return PersistenceStrategy.EMBEDDED;
+                if (fmd.getMappedBy() != null)
+                    return PersistenceStrategy.ONE_ONE;
+                FieldMetaData[] inverses = fmd.getInverseMetaDatas();
+                if (inverses.length == 1 &&
+                    inverses[0].getTypeCode() == JavaTypes.PC &&
+                    inverses[0].getMappedByMetaData() == fmd) {
+                    return PersistenceStrategy.ONE_ONE;
+                }
+                return PersistenceStrategy.MANY_ONE;
+            case JavaTypes.ARRAY:
+            case JavaTypes.COLLECTION:
+            case JavaTypes.MAP:
+                mappedBy = fmd.getMappedByMetaData();
+                if (mappedBy == null || mappedBy.getTypeCode() != JavaTypes.PC)
+                    return PersistenceStrategy.MANY_MANY;
+                return PersistenceStrategy.ONE_MANY;
+            case JavaTypes.OID:
+                return PersistenceStrategy.EMBEDDED;
+            default:
+                return PersistenceStrategy.BASIC;
+        }
+    }
+
+    /**
+     * Add basic attributes.
+     */
+    private void addBasicAttributes(FieldMetaData fmd, AnnotationBuilder ab) {
+        if (!fmd.isInDefaultFetchGroup())
+            ab.add("fetch", FetchType.LAZY);
+        if (fmd.getNullValue() == FieldMetaData.NULL_EXCEPTION)
+            ab.add("optional", false);
+    }
+
+    /**
+     * Add many-to-one attributes.
+     */
+    private void addManyToOneAttributes(FieldMetaData fmd,
+        AnnotationBuilder ab) {
+        if (!fmd.isInDefaultFetchGroup())
+            ab.add("fetch", FetchType.LAZY);
+        if (fmd.getNullValue() == FieldMetaData.NULL_EXCEPTION)
+            ab.add("optional", false);
+    }
+
+    /**
+     * Add one-to-one attributes.
+     */
+    private void addOneToOneAttributes(FieldMetaData fmd,
+        AnnotationBuilder ab) {
+        if (!fmd.isInDefaultFetchGroup())
+            ab.add("fetch", FetchType.LAZY);
+        if (fmd.getNullValue() == FieldMetaData.NULL_EXCEPTION)
+            ab.add("optional", false);
+    }
+
+    /**
+     * Add one-to-many attributes.
+     */
+    private void addOneToManyAttributes(FieldMetaData fmd,
+        AnnotationBuilder ab) {
+        if (fmd.isInDefaultFetchGroup())
+            ab.add("fetch", FetchType.EAGER);
+        addTargetEntityAttribute(fmd, ab);
+    }
+
+    /**
+     * Add many-to-many attributes.
+     */
+    private void addManyToManyAttributes(FieldMetaData fmd,
+        AnnotationBuilder ab) {
+        if (fmd.isInDefaultFetchGroup())
+            ab.add("fetch", FetchType.EAGER);
+        addTargetEntityAttribute(fmd, ab);
+    }
+
+    /**
+     * Add a target-entity attribute to collection and map fields that do
+     * not use generics.
+     */
+    private void addTargetEntityAttribute(FieldMetaData fmd,
+        AnnotationBuilder ab) {
+        Member member = fmd.getBackingMember();
+        Class[] types;
+        if (member instanceof Field)
+            types = JavaVersions.getParameterizedTypes((Field) member);
+        else if (member instanceof Method)
+            types = JavaVersions.getParameterizedTypes((Method) member);
+        else
+            types = new Class[0];
+
+        switch (fmd.getDeclaredTypeCode()) {
+            case JavaTypes.COLLECTION:
+                if (types.length != 1)
+                    ab.add("targetEntity", fmd.getElement().getDeclaredType());
+                break;
+            case JavaTypes.MAP:
+                if (types.length != 2)
+                    ab.add("targetEntity", fmd.getElement().getDeclaredType());
+                break;
+        }
+    }
+
+    /**
+     * Serialize field mapping content; this will be called before
+     * {@link #serializeValueMappingContent}. Does nothing by default.
+     */
+    protected void serializeFieldMappingContent(FieldMetaData fmd,
+        PersistenceStrategy strategy, AnnotationBuilder ab) {
+    }
+
+    /**
+     * Set mapping attributes for strategy. Sets mapped-by by default.
+     */
+    protected void addStrategyMappingAttributes(FieldMetaData fmd,
+        AnnotationBuilder ab) {
+        if (fmd.getMappedBy() != null)
+            ab.add("mappedBy", fmd.getMappedBy());
+    }
+    
+    protected Collection getObjects() {
+        List all = new ArrayList();
+        if (isQueryMode())
+            addQueryMetaDatas(all);
+        if (isMappingMode())
+            addSequenceMetaDatas(all);
+        if ((isMetaDataMode() || isMappingMode()) && _metas != null)
+            all.addAll(_metas.values());
+        if (isMappingMode())
+            addSystemMappingElements(all);
+        serializationSort(all);
+        return all;
+    }
+
+    protected void writeAnnotations(Object meta,
+        List<AnnotationBuilder> builders, Map output) {
+        List<String> annos = new ArrayList<String>();
+        for(AnnotationBuilder ab: builders)
+            annos.add(ab.toString());
+        output.put(meta, annos);        
+    }
+
+    public void serialize(Map output, int flags) throws IOException {
+        Collection all = getObjects();
+        serialize(all);
+
+        if (_clsAnnos != null)
+            for (ClassMetaData meta : _clsAnnos.keySet())
+                writeAnnotations(meta, _clsAnnos.get(meta), output);
+        if (_fldAnnos != null)
+            for (FieldMetaData meta : _fldAnnos.keySet())
+                writeAnnotations(meta, _fldAnnos.get(meta), output);
+        if (_seqAnnos != null)
+            for (SequenceMetaData meta : _seqAnnos.keySet())
+                writeAnnotations(meta, _seqAnnos.get(meta), output);
+        if (_qryAnnos != null)
+            for (QueryMetaData meta : _qryAnnos.keySet())
+                writeAnnotations(meta, _qryAnnos.get(meta), output);
+    }
+
+    public void serialize(File file, int flags) throws IOException {
+        FileWriter out = new FileWriter(file.getCanonicalPath(),
+            (flags & APPEND) > 0);
+        serialize(out, flags);
+        out.close();
+    }
+
+    public void serialize(Writer out, int flags) throws IOException {
+        Map output = new HashMap();
+        serialize(output, flags);
+
+        for(Object meta: output.keySet()) {
+            out.write("--"+meta.toString());
+            out.write("\n");
+            List<String> annos = (List<String>) output.get(meta);
+            for(String ann: annos) {
+                out.write("\t");
+                out.write(ann);
+                out.write("\n");
+            }
+        }
+    }
+
+    public void serialize(int flags) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Represents ordered set of {@link org.apache.openjpa.meta.SequenceMetaData}s with a
+     * common class scope.
+     *
+     * @author Stephen Kim
+     * @author Pinaki Poddar
+     */
+    private static class ClassSeqs
+        implements SourceTracker, Comparable<ClassSeqs>,
+        Comparator<SequenceMetaData> {
+
+        private final SequenceMetaData[] _seqs;
+
+        public ClassSeqs(List<SequenceMetaData> seqs) {
+            if (seqs == null || seqs.isEmpty())
+                throw new InternalException();
+
+            _seqs = (SequenceMetaData[]) seqs.toArray
+                (new SequenceMetaData[seqs.size()]);
+            Arrays.sort(_seqs, this);
+        }
+
+        public SequenceMetaData[] getSequences() {
+            return _seqs;
+        }
+
+        /**
+         * Compare sequence metadata on name.
+         */
+        public int compare(SequenceMetaData o1, SequenceMetaData o2) {
+            return o1.getName().compareTo(o2.getName());
+        }
+
+        public File getSourceFile() {
+            return _seqs[0].getSourceFile();
+        }
+
+        public Object getSourceScope() {
+            return _seqs[0].getSourceScope();
+        }
+
+        public int getSourceType() {
+            return _seqs[0].getSourceType();
+        }
+
+        public String getResourceName() {
+            return _seqs[0].getResourceName();
+        }
+
+        public int compareTo(ClassSeqs other) {
+            if (other == this)
+                return 0;
+            if (other == null)
+                return -1;
+            Class scope = (Class) getSourceScope();
+            Class oscope = (Class) other.getSourceScope();
+            return scope.getName().compareTo(oscope.getName());
+        }
+    }
+
+    /**
+     * Represents ordered set of {@link org.apache.openjpa.meta.QueryMetaData}s with a
+     * common class scope.
+     *
+     * @author Stephen Kim
+     * @author Pinaki Poddar
+     */
+    private static class ClassQueries
+        implements SourceTracker, Comparable<ClassQueries>,
+        Comparator<QueryMetaData> {
+
+        private final QueryMetaData[] _queries;
+
+        public ClassQueries(List<QueryMetaData> queries) {
+            if (queries == null || queries.isEmpty())
+                throw new InternalException();
+
+            _queries = (QueryMetaData[]) queries.toArray
+                (new QueryMetaData[queries.size()]);
+            Arrays.sort(_queries, this);
+        }
+
+        public QueryMetaData[] getQueries() {
+            return _queries;
+        }
+
+        /**
+         * Compare query metadata. Normal queries appear before native queries.
+         * If the given queries use same language, then their names are
+         * compared.
+         */
+        public int compare(QueryMetaData o1, QueryMetaData o2) {
+            // normal queries before native
+            if (!StringUtils.equals(o1.getLanguage(), o2.getLanguage())) {
+                if (QueryLanguages.LANG_SQL.equals(o1.getLanguage()))
+                    return 1;
+                else
+                    return -1;
+            }
+            return o1.getName().compareTo(o2.getName());
+        }
+
+        public File getSourceFile() {
+            return _queries[0].getSourceFile();
+        }
+
+        public Object getSourceScope() {
+            return _queries[0].getSourceScope();
+        }
+
+        public int getSourceType() {
+            return _queries[0].getSourceType();
+        }
+
+        public String getResourceName() {
+            return _queries[0].getResourceName();
+        }
+
+        public int compareTo(ClassQueries other) {
+            if (other == this)
+                return 0;
+            if (other == null)
+                return -1;
+            Class scope = (Class) getSourceScope();
+            Class oscope = (Class) other.getSourceScope();
+            return scope.getName().compareTo(oscope.getName());
+        }
+    }
+
+    /**
+     * Compares clases, sequences, and queries to order them for serialization.
+     * Places sequences first, then classes, then queries. Sequences and
+     * queries are ordered alphabetically by name. Classes are placed in
+     * listing order, in inheritance order within that, and in alphabetical
+     * order within that.
+     *
+     * @author Stephen Kim
+     */
+    protected class SerializationComparator
+        extends MetaDataInheritanceComparator {
+
+        public int compare(Object o1, Object o2) {
+            if (o1 == o2)
+                return 0;
+            if (o1 == null)
+                return 1;
+            if (o2 == null)
+                return -1;
+
+            int t1 = type(o1);
+            int t2 = type(o2);
+            if (t1 != t2)
+                return t1 - t2;
+
+            switch (t1) {
+                case TYPE_META:
+                    return compare((ClassMetaData) o1, (ClassMetaData) o2);
+                case TYPE_QUERY:
+                    return compare((QueryMetaData) o1, (QueryMetaData) o2);
+                case TYPE_SEQ:
+                    return compare((SequenceMetaData) o1,
+                        (SequenceMetaData) o2);
+                case TYPE_CLASS_QUERIES:
+                    return ((Comparable) o1).compareTo(o2);
+                case TYPE_CLASS_SEQS:
+                    return ((Comparable) o1).compareTo(o2);
+                default:
+                    return compareUnknown(o1, o2);
+            }
+        }
+
+        /**
+         * Compare two unrecognized elements of the same type. Throws
+         * exception by default.
+         */
+        protected int compareUnknown(Object o1, Object o2) {
+            throw new InternalException();
+        }
+
+        /**
+         * Compare between two class metadata.
+         */
+        private int compare(ClassMetaData o1, ClassMetaData o2) {
+            int li1 = o1.getListingIndex();
+            int li2 = o2.getListingIndex();
+            if (li1 == -1 && li2 == -1) {
+                MetaDataTag t1 = getEntityTag(o1);
+                MetaDataTag t2 = getEntityTag(o2);
+                if (t1.compareTo(t2) != 0)
+                    return t1.compareTo(t2);
+                int inher = super.compare(o1, o2);
+                if (inher != 0)
+                    return inher;
+                return o1.getDescribedType().getName().compareTo
+                    (o2.getDescribedType().getName());
+            }
+
+            if (li1 == -1)
+                return 1;
+            if (li2 == -1)
+                return -1;
+            return li1 - li2;
+        }
+
+        /**
+         * Compare query metadata.
+         */
+        private int compare(QueryMetaData o1, QueryMetaData o2) {
+            // normal queries before native
+            if (!StringUtils.equals(o1.getLanguage(), o2.getLanguage())) {
+                if (QueryLanguages.LANG_SQL.equals(o1.getLanguage()))
+                    return 1;
+                else
+                    return -1;
+            }
+            return o1.getName().compareTo(o2.getName());
+        }
+
+        /**
+         * Compare sequence metadata.
+         */
+        private int compare(SequenceMetaData o1, SequenceMetaData o2) {
+            return o1.getName().compareTo(o2.getName());
+        }
+    }
+
+    /**
+     * Sorts fields according to listing order, then XSD strategy order,
+     * then name order.
+     */
+    private class FieldComparator
+        implements Comparator {
+
+        public int compare(Object o1, Object o2) {
+            FieldMetaData fmd1 = (FieldMetaData) o1;
+            FieldMetaData fmd2 = (FieldMetaData) o2;
+            if (fmd1.isPrimaryKey()) {
+                if (fmd2.isPrimaryKey())
+                    return fmd1.compareTo(fmd2);
+                return -1;
+            }
+            if (fmd2.isPrimaryKey())
+                return 1;
+
+            if (fmd1.isVersion()) {
+                if (fmd2.isVersion())
+                    return compareListingOrder(fmd1, fmd2);
+				return getStrategy(fmd2) == PersistenceStrategy.BASIC ? 1 : -1;
+			}
+			if (fmd2.isVersion())
+				return getStrategy(fmd1) == PersistenceStrategy.BASIC ? -1 : 1;
+
+			int stcmp = getStrategy(fmd1).compareTo(getStrategy(fmd2));
+            if (stcmp != 0)
+                return stcmp;
+            return compareListingOrder(fmd1, fmd2);
+        }
+
+        private int compareListingOrder(FieldMetaData fmd1, FieldMetaData fmd2){
+            int lcmp = fmd1.getListingIndex() - fmd2.getListingIndex();
+            if (lcmp != 0)
+                return lcmp;
+            return fmd1.compareTo(fmd2);
+		}
+	}
+}

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataSerializer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataFactory.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataFactory.java?view=diff&rev=552358&r1=552357&r2=552358
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataFactory.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataFactory.java Sun Jul  1 12:37:04 2007
@@ -126,6 +126,15 @@
     }
 
     /**
+     * Create a new annotation serializer.
+     */
+    protected AnnotationPersistenceMetaDataSerializer
+        newAnnotationSerializer() {
+        return new AnnotationPersistenceMetaDataSerializer
+            (repos.getConfiguration());
+    }
+
+    /**
      * Return XML metadata parser, creating it if it does not already exist.
      */
     public XMLPersistenceMetaDataParser getXMLParser() {

Modified: openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_mapping.xml
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_mapping.xml?view=diff&rev=552358&r1=552357&r2=552358
==============================================================================
--- openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_mapping.xml (original)
+++ openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_mapping.xml Sun Jul  1 12:37:04 2007
@@ -539,6 +539,26 @@
                     </listitem>
                     <listitem>
                         <para>
+<literal>-metadata/-md &lt;class | package | none&gt;</literal>: Specify the
+level the metadata should be generated at. Defaults to generating a single
+package-level metadata file. Set to <literal>none</literal> to disable orm.xml
+generation.
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+<literal>-annotations/-ann &lt;true/t | false/f&gt;</literal>: Set to true to
+generate JPA annotations in generated java classes. 
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+<literal>-accessType/-access &lt;field | property&gt;</literal>: Change access
+type for generated annotations. Defaults to field access.
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
 <literal>-useSchemaName/-sn &lt;true/t | false/f&gt;</literal>: Set this flag
 to <literal>true</literal> to include the schema as well as table name in the
 name of each generated class. This can be useful when dealing with multiple
@@ -588,6 +608,13 @@
                     </listitem>
                     <listitem>
                         <para>
+<literal>-useGenericCollections/-gc &lt;true/t | false/f&gt;</literal>: Set to
+true to use generic collections on OneToMany and ManyToMany relations (requires
+JDK 1.5 or higher).
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
 <literal>-useDatastoreIdentity/-ds &lt;true/t | false/f&gt;</literal>: Set to
 <literal>true</literal> to use datastore identity for tables that have single
 numeric primary key columns. The tool typically uses application identity for
@@ -672,8 +699,9 @@
                 <para>
 Running the tool will generate <filename>.java</filename> files for each
 generated class (and its application identity class, if applicable), along with
-an <filename>orm.xml</filename> file containing the corresponding persistence 
-metadata.
+JPA annotations (if enabled by setting <literal>-annotations true</literal>),
+or an <filename>orm.xml</filename> file (if not disabled with <literal>
+-metadata none</literal>) containing the corresponding persistence metadata.
                 </para>
             </listitem>
             <listitem>
@@ -688,9 +716,9 @@
 should first compile the classes with <literal>javac</literal>, <literal>
 jikes</literal>, or your favorite Java compiler. Make sure the classes are 
 located in the directory corresponding to the <literal>-package</literal> flag 
-you gave the reverse mapping tool.  Next, move the generated <filename>
-orm.xml</filename> file to a <filename>META-INF</filename> directory within a
-directory in your classpath.  Finally, enhance the classes
+you gave the reverse mapping tool.  Next, if you have generated an <filename>
+orm.xml</filename>, move that file to a <filename>META-INF</filename> directory
+within a directory in your classpath.  Finally, enhance the classes
 if necessary (see <xref linkend="ref_guide_pc_enhance"/> ).
                 </para>
             </listitem>