v7db.files.mongodb.BSONUtils.java Source code

Java tutorial

Introduction

Here is the source code for v7db.files.mongodb.BSONUtils.java

Source

/**
 * Copyright (c) 2011-2012, Thilo Planz. All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package v7db.files.mongodb;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.BSON;
import org.bson.BSONObject;

/**
 * Utility class to work with BSON data.
 * <ul>
 * <li>performs loss-less type conversions
 * <li>supports nested fields ("a.b.c"), including auto-vivification
 * <li>fields that are null, empty array, or empty object are treated as missing
 * (setting to null removes the field)
 * </ul>
 * 
 */

public class BSONUtils {

    public static <T> T notNull(T x) {
        if (x == null)
            return x;
        if (x instanceof Map<?, ?>) {
            if (((Map<?, ?>) x).isEmpty())
                return null;
            return x;
        }

        if (x instanceof Object[]) {
            if (((Object[]) x).length == 0)
                return null;
            return x;
        }

        if (x instanceof byte[]) {
            if (((byte[]) x).length == 0)
                return null;
            return x;
        }

        if (x instanceof Collection<?>) {
            if (((Collection<?>) x).isEmpty())
                return null;
            return x;
        }

        return x;

    }

    public static Object get(BSONObject b, String fieldName) {
        if (!fieldName.contains("."))
            return notNull(b.get(fieldName));
        String[] path = StringUtils.split(fieldName, ".", 2);
        Object nested = b.get(path[0]);
        if (nested == null)
            return null;
        if (nested instanceof BSONObject)
            return get((BSONObject) nested, path[1]);
        throw new IllegalArgumentException("cannot get field `" + fieldName + "` of " + b);
    }

    private static Object getRequired(BSONObject b, String fieldName) {
        Object x = get(b, fieldName);
        if (x == null)
            throw new IllegalArgumentException("required field `" + fieldName + "` is missing in " + b);
        return x;
    }

    public static Long toLong(Object x) {
        if (x == null)
            return null;
        if (x instanceof Long)
            return (Long) x;
        if (x instanceof Integer)
            return Long.valueOf(((Integer) x).intValue());
        if (x instanceof String)
            return Long.valueOf((String) x);
        throw new IllegalArgumentException("cannot convert `" + x + "` into a Long");
    }

    static Integer toInteger(Object x) {
        if (x == null)
            return null;
        if (x instanceof Integer)
            return (Integer) x;
        if (x instanceof Long)
            return Integer.valueOf(x.toString());
        if (x instanceof String)
            return Integer.valueOf((String) x);
        throw new IllegalArgumentException("cannot convert `" + x + "` into a Long");
    }

    public static String toString(Object x) {
        if (x == null)
            return null;
        if (x instanceof String)
            return (String) x;
        if (x instanceof Number)
            return x.toString();

        throw new IllegalArgumentException("cannot convert `" + x + "` into a String");
    }

    static Boolean toBoolean(Object x) {
        if (x == null)
            return null;
        if (x instanceof Boolean)
            return (Boolean) x;
        if (x instanceof String) {
            Boolean y = BooleanUtils.toBooleanObject((String) x);
            if (y != null)
                return y;
        }
        throw new IllegalArgumentException("cannot convert `" + x + "` into a Boolean");
    }

    static Long getLong(BSONObject b, String fieldName) {
        return toLong(get(b, fieldName));
    }

    static Integer getInteger(BSONObject b, String fieldName) {
        return toInteger(get(b, fieldName));
    }

    static int getRequiredInt(BSONObject b, String fieldName) {
        return toInteger(getRequired(b, fieldName)).intValue();
    }

    public static long getRequiredLong(BSONObject b, String fieldName) {
        return toLong(getRequired(b, fieldName)).longValue();
    }

    public static String getString(BSONObject b, String fieldName) {
        return toString(get(b, fieldName));
    }

    public static BSONObject getObject(BSONObject b, String fieldName) {
        Object x = get(b, fieldName);
        if (x == null)
            return null;
        if (x instanceof BSONObject)
            return (BSONObject) x;
        throw new IllegalArgumentException("cannot convert `" + x + "` into a BSONObject");
    }

    /**
     * @return true, if the field exists, can be converted to a boolean, and is
     *         "true"
     */
    public static boolean isTrue(BSONObject b, String fieldName) {
        return Boolean.TRUE.equals(toBoolean(get(b, fieldName)));
    }

    static Object removeField(BSONObject b, String fieldName) {
        if (fieldName.contains("."))
            throw new UnsupportedOperationException("not yet implemented");
        return b.removeField(fieldName);
    }

    private static void put(BSONObject b, String fieldName, Object x) {
        x = notNull(x);
        if (x == null) {
            removeField(b, fieldName);
        } else {
            if (fieldName.contains("."))
                throw new UnsupportedOperationException("not yet implemented");
            b.put(fieldName, x);
        }
    }

    static Integer putInteger(BSONObject b, String fieldName, Object x) {
        Integer i = toInteger(x);
        put(b, fieldName, i);
        return i;
    }

    static Long putLong(BSONObject b, String fieldName, Object x) {
        Long l = toLong(x);
        put(b, fieldName, l);
        return l;
    }

    static String putString(BSONObject b, String fieldName, Object x) {
        String s = toString(x);
        put(b, fieldName, s);
        return s;
    }

    private static final Long MAX_INT = Long.valueOf(Integer.MAX_VALUE);
    private static final Long MIN_INT = Long.valueOf(Integer.MIN_VALUE);

    /**
     * stores a number as Integer, if it fits, or as a Long, if not. This saves
     * space in the database, but you lose the ability to sort or do range
     * queries.
     */
    static Number putIntegerOrLong(BSONObject b, String fieldName, Object x) {
        if (x instanceof Integer)
            return putInteger(b, fieldName, x);

        Long l = toLong(x);
        if (l == null) {
            removeField(b, fieldName);
            return null;
        }
        if (l.compareTo(MAX_INT) < 0 && l.compareTo(MIN_INT) > 0) {
            Integer i = l.intValue();
            b.put(fieldName, i);
            return i;
        }
        b.put(fieldName, l);
        return l;
    }

    /**
     * BSON objects are considered equal when their binary encoding matches
     */
    static boolean equals(BSONObject a, BSONObject b) {
        return a.keySet().equals(b.keySet()) && Arrays.equals(BSON.encode(a), BSON.encode(b));
    }

    /**
     * @return true, if the field contains (in case of an array) or is equal to
     *         (in case of a single value) the given BSONObject
     */
    static boolean contains(BSONObject b, String fieldName, BSONObject toLookFor) {
        Object list = get(b, fieldName);
        if (list == null)
            return false;
        if (list instanceof List<?>) {
            for (Object o : (List<?>) list) {
                if (o instanceof BSONObject) {
                    BSONObject x = (BSONObject) o;
                    if (equals(x, toLookFor))
                        return true;
                }
            }
            return false;
        }
        if (list instanceof Object[]) {
            for (Object o : (Object[]) list) {
                if (o instanceof BSONObject) {
                    BSONObject x = (BSONObject) o;
                    if (equals(x, toLookFor))
                        return true;
                }
            }
            return false;
        }
        if (list instanceof BSONObject) {
            BSONObject x = (BSONObject) list;
            if (equals(x, toLookFor))
                return true;
        }
        return false;

    }

    public static Object[] values(BSONObject b, String fieldName) {
        Object x = get(b, fieldName);
        if (x == null)
            return ArrayUtils.EMPTY_OBJECT_ARRAY;
        if (x instanceof List<?>)
            return ((List<?>) x).toArray();
        if (x instanceof Object[])
            return ArrayUtils.clone((Object[]) x);
        return new Object[] { x };
    }
}