All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.mongodb.ReflectionDBObject Maven / Gradle / Ivy

Go to download

The MongoDB Java Driver uber-artifact, containing mongodb-driver, mongodb-driver-core, and bson

There is a newer version: 3.1.0
Show newest version
/*
 * 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" );
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy