aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Paul Yang <TeBoring@users.noreply.github.com>2015-07-21 20:50:20 -0700
committerGravatar Paul Yang <TeBoring@users.noreply.github.com>2015-07-21 20:50:20 -0700
commit1647e63c57e2c2216da648e967686649e42a6346 (patch)
treeab932e45a0247d0bb1b35f2d08dcd646a9c67998
parent353b7a99857442c7c64a56111b3910b63237ccc8 (diff)
parent7366efd81e7f36108aa35e66fca61da8a65762c2 (diff)
Merge pull request #602 from TeBoring/objectivec
Add packTo and unpackFrom in google.protobuf.Any.
-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=(\