com.facebook.buck.json.JsonObjectHashing.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.buck.json.JsonObjectHashing.java

Source

/*
 * Copyright 2015-present Facebook, 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.facebook.buck.json;

import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.hash.Hasher;

import java.util.Collection;
import java.util.Map;
import java.util.Optional;

import javax.annotation.Nullable;

/**
 * Hashes parsed BUCK file objects.
 */
public class JsonObjectHashing {
    private static enum HashedObjectType {
        BOOLEAN, DOUBLE, FLOAT, INTEGER, LIST, LONG, SHORT, STRING, MAP, NULL
    }

    // Utility class; do not instantiate.
    private JsonObjectHashing() {
    }

    /**
     * Given a {@link Hasher} and a parsed BUCK file object, updates the Hasher
     * with the contents of the JSON object.
     */
    public static void hashJsonObject(Hasher hasher, @Nullable Object obj) {
        if (obj instanceof Map) {
            Map<?, ?> map = (Map<?, ?>) obj;
            ImmutableSortedMap.Builder<String, Optional<Object>> sortedMapBuilder = ImmutableSortedMap
                    .naturalOrder();
            for (Map.Entry<?, ?> entry : map.entrySet()) {
                Object key = entry.getKey();
                if (!(key instanceof String)) {
                    throw new RuntimeException(String.format(
                            "Keys of JSON maps are expected to be strings. Actual type: %s, contents: %s",
                            key.getClass().getName(), key));
                }
                Object value = entry.getValue();
                if (value != null) {
                    sortedMapBuilder.put((String) key, Optional.of(value));
                }
            }
            ImmutableSortedMap<String, Optional<Object>> sortedMap = sortedMapBuilder.build();
            hasher.putInt(HashedObjectType.MAP.ordinal());
            hasher.putInt(sortedMap.size());
            for (Map.Entry<String, Optional<Object>> entry : sortedMap.entrySet()) {
                hashJsonObject(hasher, entry.getKey());
                if (entry.getValue().isPresent()) {
                    hashJsonObject(hasher, entry.getValue().get());
                } else {
                    hashJsonObject(hasher, null);
                }
            }
        } else if (obj instanceof Collection) {
            Collection<?> collection = (Collection<?>) obj;
            hasher.putInt(HashedObjectType.LIST.ordinal());
            hasher.putInt(collection.size());
            for (Object collectionEntry : collection) {
                hashJsonObject(hasher, collectionEntry);
            }
        } else if (obj instanceof String) {
            hasher.putInt(HashedObjectType.STRING.ordinal());
            byte[] stringBytes = ((String) obj).getBytes(Charsets.UTF_8);
            hasher.putInt(stringBytes.length);
            hasher.putBytes(stringBytes);
        } else if (obj instanceof Boolean) {
            hasher.putInt(HashedObjectType.BOOLEAN.ordinal());
            hasher.putBoolean((boolean) obj);
        } else if (obj instanceof Number) {
            // This is gross, but it mimics the logic originally in RawParser.
            Number number = (Number) obj;
            if (number.longValue() == number.doubleValue()) {
                hasher.putInt(HashedObjectType.LONG.ordinal());
                hasher.putLong(number.longValue());
            } else {
                hasher.putInt(HashedObjectType.DOUBLE.ordinal());
                hasher.putDouble(number.doubleValue());
            }
        } else if (obj instanceof Void || obj == null) {
            hasher.putInt(HashedObjectType.NULL.ordinal());
        } else {
            throw new RuntimeException(String.format("Unsupported object %s (class %s)", obj, obj.getClass()));
        }
    }
}