Commit fbb3ef28 authored by Feng Xiao's avatar Feng Xiao

Merge Java util package to github.

parent 839b180d
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.google</groupId>
<artifactId>google</artifactId>
<version>1</version>
</parent>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>3.0.0-alpha-4-pre</version>
<packaging>bundle</packaging>
<name>Protocol Buffer Java API</name>
<description>
Protocol Buffers are a way of encoding structured data in an efficient yet
extensible format.
</description>
<inceptionYear>2008</inceptionYear>
<url>https://developers.google.com/protocol-buffers/</url>
<licenses>
<license>
<name>New BSD license</name>
<url>http://www.opensource.org/licenses/bsd-license.php</url>
<distribution>repo</distribution>
</license>
</licenses>
<scm>
<url>https://github.com/google/protobuf</url>
<connection>
scm:git:https://github.com/google/protobuf.git
</connection>
</scm>
<dependencies>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.0.0-alpha-4-pre</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymockclassextension</artifactId>
<version>2.2.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/*Test.java</include>
<include>../src/main/java/com/google/protobuf/TestUtil.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>generate-test-sources</id>
<phase>generate-test-sources</phase>
<configuration>
<tasks>
<mkdir dir="target/generated-test-sources" />
<exec executable="../../src/protoc">
<arg value="--java_out=target/generated-test-sources" />
<arg value="--proto_path=../../src" />
<arg value="--proto_path=src/test/java" />
<arg value="../../src/google/protobuf/unittest.proto" />
<arg value="../../src/google/protobuf/unittest_import.proto" />
<arg value="../../src/google/protobuf/unittest_import_public.proto" />
<arg value="src/test/java/com/google/protobuf/util/json_test.proto" />
</exec>
</tasks>
<testSourceRoot>target/generated-test-sources</testSourceRoot>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-DocURL>https://developers.google.com/protocol-buffers/</Bundle-DocURL>
<Bundle-SymbolicName>com.google.protobuf.util</Bundle-SymbolicName>
<Export-Package>com.google.protobuf.util;version=3.0.0-alpha-3</Export-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>release</id>
<distributionManagement>
<snapshotRepository>
<id>sonatype-nexus-staging</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>sonatype-nexus-staging</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.3</version>
<extensions>true</extensions>
<configuration>
<serverId>sonatype-nexus-staging</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>false</autoReleaseAfterClose>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf.util;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.FieldMask;
import com.google.protobuf.Message;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.logging.Logger;
/**
* A tree representation of a FieldMask. Each leaf node in this tree represent
* a field path in the FieldMask.
*
* <p>For example, FieldMask "foo.bar,foo.baz,bar.baz" as a tree will be:
* <pre>
* [root] -+- foo -+- bar
* | |
* | +- baz
* |
* +- bar --- baz
* </pre>
*
* <p>By representing FieldMasks with this tree structure we can easily convert
* a FieldMask to a canonical form, merge two FieldMasks, calculate the
* intersection to two FieldMasks and traverse all fields specified by the
* FieldMask in a message tree.
*/
class FieldMaskTree {
private static final Logger logger =
Logger.getLogger(FieldMaskTree.class.getName());
private static final String FIELD_PATH_SEPARATOR_REGEX = "\\.";
private static class Node {
public TreeMap<String, Node> children = new TreeMap<String, Node>();
}
private final Node root = new Node();
/** Creates an empty FieldMaskTree. */
public FieldMaskTree() {}
/** Creates a FieldMaskTree for a given FieldMask. */
public FieldMaskTree(FieldMask mask) {
mergeFromFieldMask(mask);
}
@Override
public String toString() {
return FieldMaskUtil.toString(toFieldMask());
}
/**
* Adds a field path to the tree. In a FieldMask, every field path matches the
* specified field as well as all its sub-fields. For example, a field path
* "foo.bar" matches field "foo.bar" and also "foo.bar.baz", etc. When adding
* a field path to the tree, redundant sub-paths will be removed. That is,
* after adding "foo.bar" to the tree, "foo.bar.baz" will be removed if it
* exists, which will turn the tree node for "foo.bar" to a leaf node.
* Likewise, if the field path to add is a sub-path of an existing leaf node,
* nothing will be changed in the tree.
*/
public FieldMaskTree addFieldPath(String path) {
String[] parts = path.split(FIELD_PATH_SEPARATOR_REGEX);
if (parts.length == 0) {
return this;
}
Node node = root;
boolean createNewBranch = false;
// Find the matching node in the tree.
for (String part : parts) {
// Check whether the path matches an existing leaf node.
if (!createNewBranch && node != root && node.children.isEmpty()) {
// The path to add is a sub-path of an existing leaf node.
return this;
}
if (node.children.containsKey(part)) {
node = node.children.get(part);
} else {
createNewBranch = true;
Node tmp = new Node();
node.children.put(part, tmp);
node = tmp;
}
}
// Turn the matching node into a leaf node (i.e., remove sub-paths).
node.children.clear();
return this;
}
/**
* Merges all field paths in a FieldMask into this tree.
*/
public FieldMaskTree mergeFromFieldMask(FieldMask mask) {
for (String path : mask.getPathsList()) {
addFieldPath(path);
}
return this;
}
/** Converts this tree to a FieldMask. */
public FieldMask toFieldMask() {
if (root.children.isEmpty()) {
return FieldMask.getDefaultInstance();
}
List<String> paths = new ArrayList<String>();
getFieldPaths(root, "", paths);
return FieldMask.newBuilder().addAllPaths(paths).build();
}
/** Gathers all field paths in a sub-tree. */
private void getFieldPaths(Node node, String path, List<String> paths) {
if (node.children.isEmpty()) {
paths.add(path);
return;
}
for (Entry<String, Node> entry : node.children.entrySet()) {
String childPath = path.isEmpty()
? entry.getKey() : path + "." + entry.getKey();
getFieldPaths(entry.getValue(), childPath, paths);
}
}
/**
* Adds the intersection of this tree with the given {@code path} to
* {@code output}.
*/
public void intersectFieldPath(String path, FieldMaskTree output) {
if (root.children.isEmpty()) {
return;
}
String[] parts = path.split(FIELD_PATH_SEPARATOR_REGEX);
if (parts.length == 0) {
return;
}
Node node = root;
for (String part : parts) {
if (node != root && node.children.isEmpty()) {
// The given path is a sub-path of an existing leaf node in the tree.
output.addFieldPath(path);
return;
}
if (node.children.containsKey(part)) {
node = node.children.get(part);
} else {
return;
}
}
// We found a matching node for the path. All leaf children of this matching
// node is in the intersection.
List<String> paths = new ArrayList<String>();
getFieldPaths(node, path, paths);
for (String value : paths) {
output.addFieldPath(value);
}
}
/**
* Merges all fields specified by this FieldMaskTree from {@code source} to
* {@code destination}.
*/
public void merge(Message source, Message.Builder destination,
FieldMaskUtil.MergeOptions options) {
if (source.getDescriptorForType() != destination.getDescriptorForType()) {
throw new IllegalArgumentException(
"Cannot merge messages of different types.");
}
if (root.children.isEmpty()) {
return;
}
merge(root, "", source, destination, options);
}
/** Merges all fields specified by a sub-tree from {@code source} to
* {@code destination}.
*/
private void merge(Node node, String path, Message source,
Message.Builder destination, FieldMaskUtil.MergeOptions options) {
assert source.getDescriptorForType() == destination.getDescriptorForType();
Descriptor descriptor = source.getDescriptorForType();
for (Entry<String, Node> entry : node.children.entrySet()) {
FieldDescriptor field =
descriptor.findFieldByName(entry.getKey());
if (field == null) {
logger.warning("Cannot find field \"" + entry.getKey()
+ "\" in message type " + descriptor.getFullName());
continue;
}
if (!entry.getValue().children.isEmpty()) {
if (field.isRepeated()
|| field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
logger.warning("Field \"" + field.getFullName() + "\" is not a "
+ "singluar message field and cannot have sub-fields.");
continue;
}
String childPath = path.isEmpty()
? entry.getKey() : path + "." + entry.getKey();
merge(entry.getValue(), childPath, (Message) source.getField(field),
destination.getFieldBuilder(field), options);
continue;
}
if (field.isRepeated()) {
if (options.replaceRepeatedFields()) {
destination.setField(field, source.getField(field));
} else {
for (Object element : (List) source.getField(field)) {
destination.addRepeatedField(field, element);
}
}
} else {
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
if (options.replaceMessageFields()) {
destination.setField(field, source.getField(field));
} else {
destination.getFieldBuilder(field).mergeFrom(
(Message) source.getField(field));
}
} else {
destination.setField(field, source.getField(field));
}
}
}
}
}
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf.util;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.FieldMask;
import com.google.protobuf.Internal;
import com.google.protobuf.Message;
import java.util.Arrays;
import java.util.List;
/**
* Utility helper functions to work with {@link com.google.protobuf.FieldMask}.
*/
public class FieldMaskUtil {
private static final String FIELD_PATH_SEPARATOR = ",";
private static final String FIELD_PATH_SEPARATOR_REGEX = ",";
private static final String FIELD_SEPARATOR_REGEX = "\\.";
private FieldMaskUtil() {}
/**
* Converts a FieldMask to a string.
*/
public static String toString(FieldMask fieldMask) {
StringBuilder result = new StringBuilder();
boolean first = true;
for (String value : fieldMask.getPathsList()) {
if (value.isEmpty()) {
// Ignore empty paths.
continue;
}
if (first) {
first = false;
} else {
result.append(FIELD_PATH_SEPARATOR);
}
result.append(value);
}
return result.toString();
}
/**
* Parses from a string to a FieldMask.
*/
public static FieldMask fromString(String value) {
return fromStringList(
null, Arrays.asList(value.split(FIELD_PATH_SEPARATOR_REGEX)));
}
/**
* Parses from a string to a FieldMask and validates all field paths.
*
* @throws IllegalArgumentException if any of the field path is invalid.
*/
public static FieldMask fromString(Class<? extends Message> type, String value)
throws IllegalArgumentException {
return fromStringList(
type, Arrays.asList(value.split(FIELD_PATH_SEPARATOR_REGEX)));
}
/**
* Constructs a FieldMask for a list of field paths in a certain type.
*
* @throws IllegalArgumentException if any of the field path is not valid.
*/
public static FieldMask fromStringList(
Class<? extends Message> type, List<String> paths)
throws IllegalArgumentException {
FieldMask.Builder builder = FieldMask.newBuilder();
for (String path : paths) {
if (path.isEmpty()) {
// Ignore empty field paths.
continue;
}
if (type != null && !isValid(type, path)) {
throw new IllegalArgumentException(
path + " is not a valid path for " + type);
}
builder.addPaths(path);
}
return builder.build();
}
/**
* Checks whether a given field path is valid.
*/
public static boolean isValid(Class<? extends Message> type, String path) {
String[] parts = path.split(FIELD_SEPARATOR_REGEX);
if (parts.length == 0) {
return false;
}
Descriptor descriptor =
Internal.getDefaultInstance(type).getDescriptorForType();
for (String name : parts) {
if (descriptor == null) {
return false;
}
FieldDescriptor field = descriptor.findFieldByName(name);
if (field == null) {
return false;
}
if (!field.isRepeated()
&& field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
descriptor = field.getMessageType();
} else {
descriptor = null;
}
}
return true;
}
/**
* Converts a FieldMask to its canonical form. In the canonical form of a
* FieldMask, all field paths are sorted alphabetically and redundant field
* paths are moved.
*/
public static FieldMask normalize(FieldMask mask) {
return new FieldMaskTree(mask).toFieldMask();
}
/**
* Creates an union of two FieldMasks.
*/
public static FieldMask union(FieldMask mask1, FieldMask mask2) {
return new FieldMaskTree(mask1).mergeFromFieldMask(mask2).toFieldMask();
}
/**
* Calculates the intersection of two FieldMasks.
*/
public static FieldMask intersection(FieldMask mask1, FieldMask mask2) {
FieldMaskTree tree = new FieldMaskTree(mask1);
FieldMaskTree result = new FieldMaskTree();
for (String path : mask2.getPathsList()) {
tree.intersectFieldPath(path, result);
}
return result.toFieldMask();
}
/**
* Options to customize merging behavior.
*/
public static class MergeOptions {
private boolean replaceMessageFields = false;
private boolean replaceRepeatedFields = false;
/**
* Whether to replace message fields (i.e., discard existing content in
* destination message fields) when merging.
* Default behavior is to merge the source message field into the
* destination message field.
*/
public boolean replaceMessageFields() {
return replaceMessageFields;
}
/**
* Whether to replace repeated fields (i.e., discard existing content in
* destination repeated fields) when merging.
* Default behavior is to append elements from source repeated field to the
* destination repeated field.
*/
public boolean replaceRepeatedFields() {
return replaceRepeatedFields;
}
public void setReplaceMessageFields(boolean value) {
replaceMessageFields = value;
}
public void setReplaceRepeatedFields(boolean value) {
replaceRepeatedFields = value;
}
}
/**
* Merges fields specified by a FieldMask from one message to another.
*/
public static void merge(FieldMask mask, Message source,
Message.Builder destination, MergeOptions options) {
new FieldMaskTree(mask).merge(source, destination, options);
}
/**
* Merges fields specified by a FieldMask from one message to another.
*/
public static void merge(FieldMask mask, Message source,
Message.Builder destination) {
merge(mask, source, destination, new MergeOptions());
}
}
This diff is collapsed.
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf.util;
import com.google.protobuf.FieldMask;
import protobuf_unittest.UnittestProto.NestedTestAllTypes;
import protobuf_unittest.UnittestProto.TestAllTypes;
import junit.framework.TestCase;
/** Unit tests for {@link FieldMaskUtil}. */
public class FieldMaskUtilTest extends TestCase {
public void testIsValid() throws Exception {
assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload"));
assertFalse(FieldMaskUtil.isValid(NestedTestAllTypes.class, "nonexist"));
assertTrue(FieldMaskUtil.isValid(
NestedTestAllTypes.class, "payload.optional_int32"));
assertTrue(FieldMaskUtil.isValid(
NestedTestAllTypes.class, "payload.repeated_int32"));
assertTrue(FieldMaskUtil.isValid(
NestedTestAllTypes.class, "payload.optional_nested_message"));
assertTrue(FieldMaskUtil.isValid(
NestedTestAllTypes.class, "payload.repeated_nested_message"));
assertFalse(FieldMaskUtil.isValid(
NestedTestAllTypes.class, "payload.nonexist"));
assertTrue(FieldMaskUtil.isValid(
NestedTestAllTypes.class, "payload.optional_nested_message.bb"));
// Repeated fields cannot have sub-paths.
assertFalse(FieldMaskUtil.isValid(
NestedTestAllTypes.class, "payload.repeated_nested_message.bb"));
// Non-message fields cannot have sub-paths.
assertFalse(FieldMaskUtil.isValid(
NestedTestAllTypes.class, "payload.optional_int32.bb"));
}
public void testToString() throws Exception {
assertEquals("", FieldMaskUtil.toString(FieldMask.getDefaultInstance()));
FieldMask mask = FieldMask.newBuilder().addPaths("foo").build();
assertEquals("foo", FieldMaskUtil.toString(mask));
mask = FieldMask.newBuilder().addPaths("foo").addPaths("bar").build();
assertEquals("foo,bar", FieldMaskUtil.toString(mask));
// Empty field paths are ignored.
mask = FieldMask.newBuilder().addPaths("").addPaths("foo").addPaths("").
addPaths("bar").addPaths("").build();
assertEquals("foo,bar", FieldMaskUtil.toString(mask));
}
public void testFromString() throws Exception {
FieldMask mask = FieldMaskUtil.fromString("");
assertEquals(0, mask.getPathsCount());
mask = FieldMaskUtil.fromString("foo");
assertEquals(1, mask.getPathsCount());
assertEquals("foo", mask.getPaths(0));
mask = FieldMaskUtil.fromString("foo,bar.baz");
assertEquals(2, mask.getPathsCount());
assertEquals("foo", mask.getPaths(0));
assertEquals("bar.baz", mask.getPaths(1));
// Empty field paths are ignore.
mask = FieldMaskUtil.fromString(",foo,,bar,");
assertEquals(2, mask.getPathsCount());
assertEquals("foo", mask.getPaths(0));
assertEquals("bar", mask.getPaths(1));
// Check whether the field paths are valid if a class parameter is provided.
mask = FieldMaskUtil.fromString(NestedTestAllTypes.class, ",payload");
try {
mask = FieldMaskUtil.fromString(
NestedTestAllTypes.class, "payload,nonexist");
fail("Exception is expected.");
} catch (IllegalArgumentException e) {
// Expected.
}
}
public void testUnion() throws Exception {
// Only test a simple case here and expect
// {@link FieldMaskTreeTest#testAddFieldPath} to cover all scenarios.
FieldMask mask1 = FieldMaskUtil.fromString("foo,bar.baz,bar.quz");
FieldMask mask2 = FieldMaskUtil.fromString("foo.bar,bar");
FieldMask result = FieldMaskUtil.union(mask1, mask2);
assertEquals("bar,foo", FieldMaskUtil.toString(result));
}
public void testIntersection() throws Exception {
// Only test a simple case here and expect
// {@link FieldMaskTreeTest#testIntersectFieldPath} to cover all scenarios.
FieldMask mask1 = FieldMaskUtil.fromString("foo,bar.baz,bar.quz");
FieldMask mask2 = FieldMaskUtil.fromString("foo.bar,bar");
FieldMask result = FieldMaskUtil.intersection(mask1, mask2);
assertEquals("bar.baz,bar.quz,foo.bar", FieldMaskUtil.toString(result));
}
public void testMerge() throws Exception {
// Only test a simple case here and expect
// {@link FieldMaskTreeTest#testMerge} to cover all scenarios.
NestedTestAllTypes source = NestedTestAllTypes.newBuilder()
.setPayload(TestAllTypes.newBuilder().setOptionalInt32(1234))
.build();
NestedTestAllTypes.Builder builder = NestedTestAllTypes.newBuilder();
FieldMaskUtil.merge(FieldMaskUtil.fromString("payload"), source, builder);
assertEquals(1234, builder.getPayload().getOptionalInt32());
}
}
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package json_test;
option java_package = "com.google.protobuf.util";
option java_outer_classname = "JsonTestProto";
import "google/protobuf/any.proto";
import "google/protobuf/wrappers.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/struct.proto";
message TestAllTypes {
enum NestedEnum {
FOO = 0;
BAR = 1;
BAZ = 2;
}
message NestedMessage {
int32 value = 1;
}
int32 optional_int32 = 1;
int64 optional_int64 = 2;
uint32 optional_uint32 = 3;
uint64 optional_uint64 = 4;
sint32 optional_sint32 = 5;
sint64 optional_sint64 = 6;
fixed32 optional_fixed32 = 7;
fixed64 optional_fixed64 = 8;
sfixed32 optional_sfixed32 = 9;
sfixed64 optional_sfixed64 = 10;
float optional_float = 11;
double optional_double = 12;
bool optional_bool = 13;
string optional_string = 14;
bytes optional_bytes = 15;
NestedMessage optional_nested_message = 18;
NestedEnum optional_nested_enum = 21;
// Repeated
repeated int32 repeated_int32 = 31;
repeated int64 repeated_int64 = 32;
repeated uint32 repeated_uint32 = 33;
repeated uint64 repeated_uint64 = 34;
repeated sint32 repeated_sint32 = 35;
repeated sint64 repeated_sint64 = 36;
repeated fixed32 repeated_fixed32 = 37;
repeated fixed64 repeated_fixed64 = 38;
repeated sfixed32 repeated_sfixed32 = 39;
repeated sfixed64 repeated_sfixed64 = 40;
repeated float repeated_float = 41;
repeated double repeated_double = 42;
repeated bool repeated_bool = 43;
repeated string repeated_string = 44;
repeated bytes repeated_bytes = 45;
repeated NestedMessage repeated_nested_message = 48;
repeated NestedEnum repeated_nested_enum = 51;
}
message TestMap {
// Instead of testing all combinations (too many), we only make sure all
// valid types have been used at least in one field as key and in one
// field as value.
map<int32, int32> int32_to_int32_map = 1;
map<int64, int32> int64_to_int32_map = 2;
map<uint32, int32> uint32_to_int32_map = 3;
map<uint64, int32> uint64_to_int32_map = 4;
map<sint32, int32> sint32_to_int32_map = 5;
map<sint64, int32> sint64_to_int32_map = 6;
map<fixed32, int32> fixed32_to_int32_map = 7;
map<fixed64, int32> fixed64_to_int32_map = 8;
map<sfixed32, int32> sfixed32_to_int32_map = 9;
map<sfixed64, int32> sfixed64_to_int32_map = 10;
map<bool, int32> bool_to_int32_map = 11;
map<string, int32> string_to_int32_map = 12;
map<int32, int64> int32_to_int64_map = 101;
map<int32, uint32> int32_to_uint32_map = 102;
map<int32, uint64> int32_to_uint64_map = 103;
map<int32, sint32> int32_to_sint32_map = 104;
map<int32, sint64> int32_to_sint64_map = 105;
map<int32, fixed32> int32_to_fixed32_map = 106;
map<int32, fixed64> int32_to_fixed64_map = 107;
map<int32, sfixed32> int32_to_sfixed32_map = 108;
map<int32, sfixed64> int32_to_sfixed64_map = 109;
map<int32, float> int32_to_float_map = 110;
map<int32, double> int32_to_double_map = 111;
map<int32, bool> int32_to_bool_map = 112;
map<int32, string> int32_to_string_map = 113;
map<int32, bytes> int32_to_bytes_map = 114;
map<int32, TestAllTypes.NestedMessage> int32_to_message_map = 115;
map<int32, TestAllTypes.NestedEnum> int32_to_enum_map = 116;
}
message TestWrappers {
google.protobuf.Int32Value int32_value = 1;
google.protobuf.UInt32Value uint32_value = 2;
google.protobuf.Int64Value int64_value = 3;
google.protobuf.UInt64Value uint64_value = 4;
google.protobuf.FloatValue float_value = 5;
google.protobuf.DoubleValue double_value = 6;
google.protobuf.BoolValue bool_value = 7;
google.protobuf.StringValue string_value = 8;
google.protobuf.BytesValue bytes_value = 9;
}
message TestTimestamp {
google.protobuf.Timestamp timestamp_value = 1;
}
message TestDuration {
google.protobuf.Duration duration_value = 1;
}
message TestFieldMask {
google.protobuf.FieldMask field_mask_value = 1;
}
message TestStruct {
google.protobuf.Struct struct_value = 1;
}
message TestAny {
google.protobuf.Any any_value = 1;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment