com.google.cloud.Structs Maven / Gradle / Ivy
Show all versions of google-cloud-core Show documentation
/*
* Copyright 2016 Google LLC
*
* 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.google.cloud;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.api.client.util.Types;
import com.google.api.core.InternalApi;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.protobuf.ListValue;
import com.google.protobuf.NullValue;
import com.google.protobuf.Struct;
import com.google.protobuf.Value;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* This class contains static utility methods that operate on or return protobuf's {@code Struct}
* objects. This is considered an internal class and implementation detail.
*/
@InternalApi
public final class Structs {
private Structs() {}
/**
* This class wraps a protobuf's {@code Struct} object and offers a map interface to it, hiding
* protobuf types.
*/
private static final class StructMap extends AbstractMap {
private final Set> entrySet;
private StructMap(Struct struct) {
this.entrySet = new StructSet(struct);
}
private static final class StructSet extends AbstractSet> {
private static Entry valueToObject(Entry entry) {
return new AbstractMap.SimpleEntry<>(
entry.getKey(), Structs.valueToObject(entry.getValue()));
}
private final Struct struct;
private StructSet(Struct struct) {
this.struct = struct;
}
@Override
public Iterator> iterator() {
return Iterators.transform(
struct.getFieldsMap().entrySet().iterator(), StructSet::valueToObject);
}
@Override
public int size() {
return struct.getFieldsMap().size();
}
}
@Override
public Set> entrySet() {
return entrySet;
}
}
/** Returns an unmodifiable map view of the {@link Struct} parameter. */
public static Map asMap(Struct struct) {
return new StructMap(checkNotNull(struct));
}
/**
* Creates a new {@link Struct} object given the content of the provided {@code map} parameter.
*
* Notice that all numbers (int, long, float and double) are serialized as double values. Enums
* are serialized as strings.
*/
public static Struct newStruct(Map map) {
Map valueMap = Maps.transformValues(checkNotNull(map), Structs::objectToValue);
return Struct.newBuilder().putAllFields(valueMap).build();
}
private static Object valueToObject(Value value) {
switch (value.getKindCase()) {
case NULL_VALUE:
return null;
case NUMBER_VALUE:
return value.getNumberValue();
case STRING_VALUE:
return value.getStringValue();
case BOOL_VALUE:
return value.getBoolValue();
case STRUCT_VALUE:
return new StructMap(value.getStructValue());
case LIST_VALUE:
return Lists.transform(value.getListValue().getValuesList(), Structs::valueToObject);
default:
throw new IllegalArgumentException(String.format("Unsupported protobuf value %s", value));
}
}
@SuppressWarnings("unchecked")
private static Value objectToValue(final Object obj) {
Value.Builder builder = Value.newBuilder();
if (obj == null) {
builder.setNullValue(NullValue.NULL_VALUE);
return builder.build();
}
Class> objClass = obj.getClass();
if (obj instanceof String) {
builder.setStringValue((String) obj);
} else if (obj instanceof Number) {
builder.setNumberValue(((Number) obj).doubleValue());
} else if (obj instanceof Boolean) {
builder.setBoolValue((Boolean) obj);
} else if (obj instanceof Iterable> || objClass.isArray()) {
builder.setListValue(
ListValue.newBuilder()
.addAllValues(Iterables.transform(Types.iterableOf(obj), Structs::objectToValue)));
} else if (objClass.isEnum()) {
builder.setStringValue(((Enum>) obj).name());
} else if (obj instanceof Map) {
Map map = (Map) obj;
builder.setStructValue(newStruct(map));
} else {
throw new IllegalArgumentException(String.format("Unsupported protobuf value %s", obj));
}
return builder.build();
}
}