Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* Copyright (C) 2010 Olafur Gauti Gudmundsson Licensed 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.mongodb.morphia.mapping;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.DBRef;
import org.bson.BSONEncoder;
import org.bson.BasicBSONEncoder;
import org.mongodb.morphia.Datastore;
import org.mongodb.morphia.EntityInterceptor;
import org.mongodb.morphia.Key;
import org.mongodb.morphia.annotations.Converters;
import org.mongodb.morphia.annotations.Embedded;
import org.mongodb.morphia.annotations.NotSaved;
import org.mongodb.morphia.annotations.PostLoad;
import org.mongodb.morphia.annotations.PreLoad;
import org.mongodb.morphia.annotations.PrePersist;
import org.mongodb.morphia.annotations.PreSave;
import org.mongodb.morphia.annotations.Property;
import org.mongodb.morphia.annotations.Reference;
import org.mongodb.morphia.annotations.Serialized;
import org.mongodb.morphia.converters.CustomConverters;
import org.mongodb.morphia.converters.TypeConverter;
import org.mongodb.morphia.logging.Logger;
import org.mongodb.morphia.logging.MorphiaLoggerFactory;
import org.mongodb.morphia.mapping.cache.EntityCache;
import org.mongodb.morphia.mapping.lazy.LazyFeatureDependencies;
import org.mongodb.morphia.mapping.lazy.LazyProxyFactory;
import org.mongodb.morphia.mapping.lazy.proxy.ProxiedEntityReference;
import org.mongodb.morphia.mapping.lazy.proxy.ProxyHelper;
import org.mongodb.morphia.query.Query;
import org.mongodb.morphia.query.QueryImpl;
import org.mongodb.morphia.query.ValidationException;
import java.io.IOException;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import static java.lang.String.format;
import static org.mongodb.morphia.utils.ReflectionUtils.getParameterizedClass;
import static org.mongodb.morphia.utils.ReflectionUtils.implementsInterface;
import static org.mongodb.morphia.utils.ReflectionUtils.isPropertyType;
/**
*
This is the heart of Morphia and takes care of mapping from/to POJOs/DBObjects
This class is thread-safe and keeps various
* "cached" data which should speed up processing.
*
* @author Olafur Gauti Gudmundsson
* @author Scott Hernandez
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public class Mapper {
/**
* The @{@link org.mongodb.morphia.annotations.Id} field name that is stored with mongodb.
*/
public static final String ID_KEY = "_id";
/**
* Special name that can never be used. Used as default for some fields to indicate default state.
*/
public static final String IGNORED_FIELDNAME = ".";
/**
* Special field used by morphia to support various possibly loading issues; will be replaced when discriminators are implemented to
* support polymorphism
*/
public static final String CLASS_NAME_FIELDNAME = "className";
private static final Logger LOG = MorphiaLoggerFactory.get(Mapper.class);
/**
* Set of classes that registered by this mapper
*/
private final Map mappedClasses = new ConcurrentHashMap();
private final ConcurrentHashMap> mappedClassesByCollection = new ConcurrentHashMap>();
//EntityInterceptors; these are called after EntityListeners and lifecycle methods on an Entity, for all Entities
private final List interceptors = new LinkedList();
//A general cache of instances of classes; used by MappedClass for EntityListener(s)
private final Map instanceCache = new ConcurrentHashMap();
// TODO: make these configurable
private final LazyProxyFactory proxyFactory = LazyFeatureDependencies.createDefaultProxyFactory();
private final org.mongodb.morphia.converters.Converters converters;
private MapperOptions opts = new MapperOptions();
/**
* Creates a Mapper with the given options.
*
* @param opts the options to use
*/
public Mapper(final MapperOptions opts) {
this();
this.opts = opts;
}
/**
* Creates a Mapper with default options
*
* @see MapperOptions
*/
public Mapper() {
converters = new CustomConverters(this);
}
/**
* Creates a new Mapper with the given options and a Mapper to copy. This is effectively a copy constructor that allows a developer
* to override the options.
*
* @param options the options to use
* @param mapper the collection of MappedClasses to add
*/
public Mapper(final MapperOptions options, final Mapper mapper) {
this(options);
for (final MappedClass mappedClass : mapper.getMappedClasses()) {
addMappedClass(mappedClass, false);
}
}
/**
* Adds an {@link EntityInterceptor}
*
* @param ei the interceptor to add
*/
public void addInterceptor(final EntityInterceptor ei) {
interceptors.add(ei);
}
/**
* Creates a MappedClass and validates it.
*
* @param c the Class to map
* @return the MappedClass for the given Class
*/
public MappedClass addMappedClass(final Class c) {
MappedClass mappedClass = mappedClasses.get(c.getName());
if (mappedClass == null) {
mappedClass = new MappedClass(c, this);
return addMappedClass(mappedClass, true);
}
return mappedClass;
}
/**
* Creates a cache for tracking entities seen during processing
*
* @return the cache
*/
public EntityCache createEntityCache() {
return getOptions().getCacheFactory().createCache();
}
/**
* Converts a DBObject back to a type-safe java object (POJO)
*
* @param the type of the entity
* @param datastore the Datastore to use when fetching this reference
* @param entityClass The type to return, or use; can be overridden by the @see Mapper.CLASS_NAME_FIELDNAME in the DBObject
* @param dbObject the DBObject containing the document from mongodb
* @param cache the EntityCache to use
* @return the new entity
* @see Mapper#CLASS_NAME_FIELDNAME
*/
public T fromDBObject(final Datastore datastore, final Class entityClass, final DBObject dbObject, final EntityCache cache) {
if (dbObject == null) {
final Throwable t = new Throwable();
LOG.error("A null reference was passed in for the dbObject", t);
return null;
}
T entity;
entity = opts.getObjectFactory().createInstance(entityClass, dbObject);
entity = fromDb(datastore, dbObject, entity, cache);
return entity;
}
/**
* Finds any subtypes for the given MappedClass.
*
* @param mc the parent type
*
* @return the list of subtypes
* @since 1.3
*/
public List getSubTypes(final MappedClass mc) {
List subtypes = new ArrayList();
for (MappedClass mappedClass : getMappedClasses()) {
if (mappedClass.isSubType(mc)) {
subtypes.add(mappedClass);
}
}
return subtypes;
}
/**
* Converts an entity (POJO) to a DBObject. A special field will be added to keep track of the class type.
*
* @param datastore the Datastore to use when fetching this reference
* @param dbObject the DBObject
* @param the type of the referenced entity
* @return the entity
*/
T fromDBObject(final Datastore datastore, final DBObject dbObject) {
if (dbObject.containsField(CLASS_NAME_FIELDNAME)) {
T entity = opts.getObjectFactory().createInstance(null, dbObject);
entity = fromDb(datastore, dbObject, entity, createEntityCache());
return entity;
} else {
throw new MappingException(format("The DBOBbject does not contain a %s key. Determining entity type is impossible.",
CLASS_NAME_FIELDNAME));
}
}
/**
* Converts a DBObject back to a type-safe java object (POJO)
*
* @param the type of the entity
* @param datastore the Datastore to use when fetching this reference
* @param dbObject the DBObject containing the document from mongodb
* @param entity the instance to populate
* @param cache the EntityCache to use
* @return the entity
*/
public T fromDb(final Datastore datastore, final DBObject dbObject, final T entity, final EntityCache cache) {
//hack to bypass things and just read the value.
if (entity instanceof MappedField) {
readMappedField(datastore, (MappedField) entity, entity, cache, dbObject);
return entity;
}
// check the history key (a key is the namespace + id)
if (dbObject.containsField(ID_KEY) && getMappedClass(entity).getIdField() != null
&& getMappedClass(entity).getEntityAnnotation() != null) {
final Key key = new Key(entity.getClass(), getCollectionName(entity.getClass()), dbObject.get(ID_KEY));
final T cachedInstance = cache.getEntity(key);
if (cachedInstance != null) {
return cachedInstance;
} else {
cache.putEntity(key, entity); // to avoid stackOverflow in recursive refs
}
}
if (entity instanceof Map) {
Map map = (Map) entity;
for (String key : dbObject.keySet()) {
Object o = dbObject.get(key);
map.put(key, (o instanceof DBObject) ? fromDBObject(datastore, (DBObject) o) : o);
}
} else if (entity instanceof Collection) {
Collection