aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTeBoring <teboring@google.com>2015-07-15 16:16:08 -0700
committerTeBoring <teboring@google.com>2015-07-21 15:45:02 -0700
commit7366efd81e7f36108aa35e66fca61da8a65762c2 (patch)
treec3b05157928bf27405115aea5835055066cb7022
parentfde6e89f99eda04a4f1b8677bcea07e6c2040405 (diff)
downloadprotobuf-7366efd81e7f36108aa35e66fca61da8a65762c2.tar.gz
protobuf-7366efd81e7f36108aa35e66fca61da8a65762c2.tar.bz2
protobuf-7366efd81e7f36108aa35e66fca61da8a65762c2.zip
Add packFrom, unpackTo and is in google.protobuf.Any.
The previous two methods make it easy to transform between any and normal message. unPackeTo will throw error if the type url in any doesn't match the type of the message to be transformed to. is checks any's type url matches the give GPBMessage type.
-rwxr-xr-xgenerate_descriptor_proto.sh1
-rw-r--r--objectivec/GPBWellKnownTypes.h22
-rw-r--r--objectivec/GPBWellKnownTypes.m49
-rw-r--r--objectivec/Tests/GPBWellKnownTypesTest.m53
-rwxr-xr-xobjectivec/generate_descriptors_proto.sh1
5 files changed, 122 insertions, 4 deletions
diff --git a/generate_descriptor_proto.sh b/generate_descriptor_proto.sh
index 89449e10..b6e6e07b 100755
--- a/generate_descriptor_proto.sh
+++ b/generate_descriptor_proto.sh
@@ -27,7 +27,6 @@ __EOF__
fi
cd src
-make $@ google/protobuf/stubs/pbconfig.h
declare -a RUNTIME_PROTO_FILES=(\
google/protobuf/any.proto \
diff --git a/objectivec/GPBWellKnownTypes.h b/objectivec/GPBWellKnownTypes.h
index c98594a2..050f85f6 100644
--- a/objectivec/GPBWellKnownTypes.h
+++ b/objectivec/GPBWellKnownTypes.h
@@ -30,8 +30,10 @@
#import <Foundation/Foundation.h>
-#import "google/protobuf/Timestamp.pbobjc.h"
+#import "google/protobuf/Any.pbobjc.h"
#import "google/protobuf/Duration.pbobjc.h"
+#import "google/protobuf/Timestamp.pbobjc.h"
+
NS_ASSUME_NONNULL_BEGIN
@@ -49,4 +51,22 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970;
@end
+// Extension to GPBAny to support packing and unpacking for arbitrary messages.
+@interface GPBAny (GPBWellKnownTypes)
+// Initialize GPBAny instance with the given message. e.g., for google.protobuf.foo, type
+// url will be "type.googleapis.com/google.protobuf.foo" and value will be serialized foo.
+- (instancetype)initWithMessage:(GPBMessage*)message;
+// Serialize the given message to the value in GPBAny. Type url will also be updated.
+- (void)setMessage:(GPBMessage*)message;
+// Parse the value in GPBAny to the given message. If messageClass message doesn't match the
+// type url in GPBAny, nil is returned.
+- (GPBMessage*)messageOfClass:(Class)messageClass;
+// True if the given type matches the type url in GPBAny.
+- (BOOL)wrapsMessageOfClass:(Class)messageClass;
+@end
+
+// Common prefix of type url in GPBAny, which is @"type.googleapis.com/". All valid
+// type urls in any should start with this prefix.
+extern NSString *const GPBTypeGoogleApisComPrefix;
+
NS_ASSUME_NONNULL_END
diff --git a/objectivec/GPBWellKnownTypes.m b/objectivec/GPBWellKnownTypes.m
index fe02f5de..b48f8a53 100644
--- a/objectivec/GPBWellKnownTypes.m
+++ b/objectivec/GPBWellKnownTypes.m
@@ -115,3 +115,52 @@ static int32_t SecondsAndNanosFromTimeIntervalSince1970(NSTimeInterval time,
}
@end
+
+NSString *const GPBTypeGoogleApisComPrefix = @"type.googleapis.com/";
+
+@implementation GPBAny (GBPWellKnownTypes)
+
+- (instancetype)initWithMessage:(GPBMessage*)message {
+ self = [super init];
+ if (self) {
+ [self setMessage:message];
+ }
+ return self;
+}
+
+- (NSString*)typeName {
+ NSAssert([self.typeURL hasPrefix:GPBTypeGoogleApisComPrefix],
+ @"Invalid any type url (%@).", self.typeURL);
+ if (![self.typeURL hasPrefix:GPBTypeGoogleApisComPrefix]) {
+ return nil;
+ }
+ return [self.typeURL substringFromIndex:[GPBTypeGoogleApisComPrefix length]];
+}
+
+- (void)setMessage:(GPBMessage*)message {
+ self.typeURL = [GPBTypeGoogleApisComPrefix stringByAppendingString:message.descriptor.name];
+ self.value = message.data;
+}
+
+- (GPBMessage*)messageOfClass:(Class)messageClass {
+ if ([self wrapsMessageOfClass:messageClass]) {
+ GPBMessage* message = [messageClass message];
+ [message mergeFromData:self.value extensionRegistry:nil];
+ return message;
+ } else {
+ return nil;
+ }
+}
+
+- (BOOL)wrapsMessageOfClass:(Class)messageClass {
+ NSAssert([messageClass isSubclassofClass:[GPBMessage class]],
+ @"Given class (%@) is not a subclass of GPBMessage",
+ [messageClass name]);
+ if (![messageClass isSubclassOfClass:[GPBMessage class]]) {
+ return NO;
+ }
+ return [[self typeName] isEqualToString:messageClass.descriptor.name];
+}
+
+@end
+
diff --git a/objectivec/Tests/GPBWellKnownTypesTest.m b/objectivec/Tests/GPBWellKnownTypesTest.m
index 78f4e637..48c875aa 100644
--- a/objectivec/Tests/GPBWellKnownTypesTest.m
+++ b/objectivec/Tests/GPBWellKnownTypesTest.m
@@ -28,7 +28,9 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#import "google/protobuf/Unittest.pbobjc.h"
#import "GPBWellKnownTypes.h"
+#import "GPBTestUtilities.h"
#import <XCTest/XCTest.h>
@@ -38,7 +40,7 @@ static const NSTimeInterval kFutureOffsetInterval = 15000;
// Nanosecond time accuracy
static const NSTimeInterval kTimeAccuracy = 1e-9;
-@interface WellKnownTypesTest : XCTestCase
+@interface WellKnownTypesTest : GPBTestCase
@end
@implementation WellKnownTypesTest
@@ -99,4 +101,53 @@ static const NSTimeInterval kTimeAccuracy = 1e-9;
[duration2 release];
}
+- (void)testAnyPackingAndUnpacking {
+ TestAllTypes *from = [TestAllTypes message];
+ [self setAllFields:from repeatedCount:1];
+ NSData *data = from.data;
+
+ // Test initWithMessage
+ GPBAny *anyInited = [[GPBAny alloc] initWithMessage:from];
+ XCTAssertEqualObjects(
+ [GPBTypeGoogleApisComPrefix stringByAppendingString:from.descriptor.name],
+ anyInited.typeURL);
+ XCTAssertEqualObjects(data, anyInited.value);
+ [anyInited release];
+
+ // Test setMessage.
+ GPBAny *any = [GPBAny message];
+ [any setMessage:from];
+ XCTAssertEqualObjects(
+ [GPBTypeGoogleApisComPrefix stringByAppendingString:from.descriptor.name],
+ any.typeURL);
+ XCTAssertEqualObjects(data, any.value);
+
+ // Test messageOfClass
+ TestAllTypes *to = (TestAllTypes*)[any messageOfClass:[TestAllTypes class]];
+ XCTAssertEqualObjects(from, to);
+ XCTAssertEqual([any messageOfClass:[ForeignMessage class]], nil);
+ XCTAssertEqual([[GPBAny message] messageOfClass:[TestAllTypes class]], nil);
+
+ // Test setMessage with another type.
+ ForeignMessage *from2 = [ForeignMessage message];
+ [any setMessage:from2];
+ XCTAssertEqualObjects(
+ [GPBTypeGoogleApisComPrefix stringByAppendingString:from2.descriptor.name],
+ any.typeURL);
+ XCTAssertEqual(0UL, [any.value length]);
+
+ // Test wrapsMessageOfClass
+ XCTAssertTrue([any wrapsMessageOfClass:[from2 class]]);
+ XCTAssertFalse([any wrapsMessageOfClass:[from class]]);
+#if !defined(NS_BLOCK_ASSERTIONS)
+ // If assert is enabled, throw exception when the passed message class to
+ // wrapsMessageOfClass is not a child of GPBMessage.
+ XCTAssertThrows([any wrapsMessageOfClass:[NSString class]]);
+#else
+ // If assert is disabled, return false when the passed message class to
+ // wrapsMessageOfClass is not a child of GPBMessage.
+ XCTAssertFalse([any wrapsMessageOfClass:[NSString class]]);
+#endif
+}
+
@end
diff --git a/objectivec/generate_descriptors_proto.sh b/objectivec/generate_descriptors_proto.sh
index f2ed00b7..b3ecf398 100755
--- a/objectivec/generate_descriptors_proto.sh
+++ b/objectivec/generate_descriptors_proto.sh
@@ -33,7 +33,6 @@ fi
# Make sure the compiler is current.
cd src
-make $@ google/protobuf/stubs/pbconfig.h
make $@ protoc
declare -a RUNTIME_PROTO_FILES=(\