com.mongodb.ReflectionDBObject Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mongo-java-driver Show documentation
Show all versions of mongo-java-driver Show documentation
The MongoDB Java Driver uber-artifact, containing mongodb-driver, mongodb-driver-core, and bson
/*
* Copyright (c) 2008-2014 MongoDB, Inc.
*
* 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 com.mongodb;
import org.bson.BSONObject;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
* This class enables to map simple Class fields to a BSON object fields
*/
public abstract class ReflectionDBObject implements DBObject {
@Override
public Object get(final String key) {
return getWrapper().get( this , key );
}
@Override
public Set keySet(){
return getWrapper().keySet();
}
@Deprecated
@Override
public boolean containsKey(final String s) {
return containsField(s);
}
@Override
public boolean containsField(final String s) {
return getWrapper().containsKey(s);
}
@Override
public Object put(final String key, final Object v) {
return getWrapper().set( this , key , v );
}
@SuppressWarnings("unchecked")
@Override
public void putAll(final Map m) {
for ( Map.Entry entry : (Set)m.entrySet() ){
put( entry.getKey().toString() , entry.getValue() );
}
}
@Override
public void putAll(final BSONObject o) {
for ( String k : o.keySet() ){
put( k , o.get( k ) );
}
}
/**
* Gets the _id
*
* @return the _id of this document
*/
public Object get_id(){
return _id;
}
/**
* Sets the _id
*
* @param id the unique identifier for this DBObject
*/
public void set_id( Object id ){
_id = id;
}
@Override
public boolean isPartialObject(){
return false;
}
@SuppressWarnings("unchecked")
@Override
public Map toMap() {
Map m = new HashMap();
Iterator i = this.keySet().iterator();
while (i.hasNext()) {
Object s = i.next();
m.put(s, this.get(s+""));
}
return m;
}
/**
* ReflectionDBObjects can't be partial. This operation is not supported.
*/
@Override
public void markAsPartialObject(){
throw new RuntimeException( "ReflectionDBObjects can't be partial" );
}
/**
* This operation is not supported. Throws a {@code RuntimeException}.
*/
public Object removeField( String key ){
throw new RuntimeException( "can't remove from a ReflectionDBObject" );
}
JavaWrapper getWrapper(){
if ( _wrapper != null )
return _wrapper;
_wrapper = getWrapper( this.getClass() );
return _wrapper;
}
JavaWrapper _wrapper;
Object _id;
/**
* Represents a wrapper around the DBObject to interface with the Class fields
*/
public static class JavaWrapper {
JavaWrapper( Class c ){
_class = c;
_name = c.getName();
_fields = new TreeMap();
for ( Method m : c.getMethods() ){
if ( ! ( m.getName().startsWith( "get" ) || m.getName().startsWith( "set" ) ) )
continue;
String name = m.getName().substring(3);
if ( name.length() == 0 || IGNORE_FIELDS.contains( name ) )
continue;
Class type = m.getName().startsWith( "get" ) ? m.getReturnType() : m.getParameterTypes()[0];
FieldInfo fi = _fields.get( name );
if ( fi == null ){
fi = new FieldInfo( name , type );
_fields.put( name , fi );
}
if ( m.getName().startsWith( "get" ) )
fi._getter = m;
else
fi._setter = m;
}
Set names = new HashSet( _fields.keySet() );
for ( String name : names )
if ( ! _fields.get( name ).ok() )
_fields.remove( name );
_keys = Collections.unmodifiableSet( _fields.keySet() );
}
/**
* Gets all the fields on this object.
*
* @return a Set of all the field names.
*/
public Set keySet(){
return _keys;
}
/**
* Whether the document this represents contains the given field.
*
* @param key a field name
* @return true if the key exists
* @deprecated
*/
@Deprecated
public boolean containsKey( String key ){
return _keys.contains( key );
}
/**
* Gets the value for the given field from the given document.
*
* @param document a ReflectionDBObject representing a MongoDB document
* @param fieldName the name of the field to get the value for
* @return the value for the given field name
*/
public Object get(final ReflectionDBObject document, final String fieldName) {
FieldInfo i = _fields.get(fieldName);
if ( i == null )
return null;
try {
return i._getter.invoke( document );
}
catch ( Exception e ){
throw new RuntimeException( "could not invoke getter for [" + fieldName + "] on [" + _name + "]" , e );
}
}
/**
* Adds or sets the given field to the given value on the document.
*
* @param t a ReflectionDBObject representing a MongoDB document
* @param name the name of the field to get the value for
* @param val the value to set the field to
* @return the result of setting this value
*/
public Object set(ReflectionDBObject t, String name, Object val) {
FieldInfo i = _fields.get( name );
if ( i == null )
throw new IllegalArgumentException( "no field [" + name + "] on [" + _name + "]" );
try {
return i._setter.invoke( t , val );
}
catch ( Exception e ){
throw new RuntimeException( "could not invoke setter for [" + name + "] on [" + _name + "]" , e );
}
}
Class getInternalClass( String path ){
String cur = path;
String next = null;
final int idx = path.indexOf( "." );
if ( idx >= 0 ){
cur = path.substring( 0 , idx );
next = path.substring( idx + 1 );
}
FieldInfo fi = _fields.get( cur );
if ( fi == null )
return null;
if ( next == null )
return fi._class;
JavaWrapper w = getWrapperIfReflectionObject( fi._class );
if ( w == null )
return null;
return w.getInternalClass( next );
}
final Class _class;
final String _name;
final Map _fields;
final Set _keys;
}
static class FieldInfo {
FieldInfo( String name , Class c ){
_name = name;
_class = c;
}
boolean ok(){
return
_getter != null &&
_setter != null;
}
final String _name;
final Class _class;
Method _getter;
Method _setter;
}
/**
* Returns the wrapper if this object can be assigned from this class.
*
* @param c the class to be wrapped
* @return the wrapper
*/
public static JavaWrapper getWrapperIfReflectionObject( Class c ){
if ( ReflectionDBObject.class.isAssignableFrom( c ) )
return getWrapper( c );
return null;
}
/**
* Returns an existing Wrapper instance associated with a class, or creates a new one.
*
* @param c the class to be wrapped
* @return the wrapped
*/
public static JavaWrapper getWrapper( Class c ){
JavaWrapper w = _wrappers.get( c );
if ( w == null ){
w = new JavaWrapper( c );
_wrappers.put( c , w );
}
return w;
}
private static final Map _wrappers = Collections.synchronizedMap( new HashMap() );
private static final Set IGNORE_FIELDS = new HashSet();
static {
IGNORE_FIELDS.add( "Int" );
}
}