aboutsummaryrefslogtreecommitdiff
path: root/objectivec
diff options
context:
space:
mode:
authorThomas Van Lenten <thomasvl@google.com>2016-08-16 11:26:49 -0400
committerThomas Van Lenten <thomasvl@google.com>2016-09-08 11:59:57 -0400
commit337ec3065f98d6f048f92b3a864f65383a2549d8 (patch)
tree23ab2fea2b0d97cc64b0253fd313ce9bad1bbaf9 /objectivec
parent4bc16578537495b5ee010d89f2909858312210ac (diff)
downloadprotobuf-337ec3065f98d6f048f92b3a864f65383a2549d8.tar.gz
protobuf-337ec3065f98d6f048f92b3a864f65383a2549d8.tar.bz2
protobuf-337ec3065f98d6f048f92b3a864f65383a2549d8.zip
Add ObjC helpers for Any WKT.
- Capture the ObjC prefix used when generating the the file. - Track the containing type on descriptors. - Mark descriptors where the message class name got a suffix added to it. - Expose a fullName property on Descriptors. - Add helpers for packing/unpacking Any messages. - Bump the ObjC runtime version number. Since we added methods and invoke them in the generated code, ensure the code is running against a matching version. Otherwise, someone could compile against headers, but run with a framework that is older and get unknown selector failures. This should trip clearer messaging. Fixes https://github.com/google/protobuf/issues/1674
Diffstat (limited to 'objectivec')
-rwxr-xr-xobjectivec/DevTools/compile_testing_protos.sh1
-rw-r--r--objectivec/GPBBootstrap.h2
-rw-r--r--objectivec/GPBDescriptor.h9
-rw-r--r--objectivec/GPBDescriptor.m114
-rw-r--r--objectivec/GPBDescriptor_PackagePrivate.h5
-rw-r--r--objectivec/GPBWellKnownTypes.h125
-rw-r--r--objectivec/GPBWellKnownTypes.m135
-rw-r--r--objectivec/Tests/GPBDescriptorTests.m29
-rw-r--r--objectivec/Tests/GPBUnittestProtos.m1
-rw-r--r--objectivec/Tests/GPBWellKnownTypesTest.m56
-rw-r--r--objectivec/google/protobuf/Any.pbobjc.h2
-rw-r--r--objectivec/google/protobuf/Any.pbobjc.m1
-rw-r--r--objectivec/google/protobuf/Api.pbobjc.h2
-rw-r--r--objectivec/google/protobuf/Api.pbobjc.m1
-rw-r--r--objectivec/google/protobuf/Duration.pbobjc.h2
-rw-r--r--objectivec/google/protobuf/Duration.pbobjc.m1
-rw-r--r--objectivec/google/protobuf/Empty.pbobjc.h2
-rw-r--r--objectivec/google/protobuf/Empty.pbobjc.m1
-rw-r--r--objectivec/google/protobuf/FieldMask.pbobjc.h2
-rw-r--r--objectivec/google/protobuf/FieldMask.pbobjc.m1
-rw-r--r--objectivec/google/protobuf/SourceContext.pbobjc.h2
-rw-r--r--objectivec/google/protobuf/SourceContext.pbobjc.m1
-rw-r--r--objectivec/google/protobuf/Struct.pbobjc.h2
-rw-r--r--objectivec/google/protobuf/Struct.pbobjc.m1
-rw-r--r--objectivec/google/protobuf/Timestamp.pbobjc.h2
-rw-r--r--objectivec/google/protobuf/Timestamp.pbobjc.m1
-rw-r--r--objectivec/google/protobuf/Type.pbobjc.h2
-rw-r--r--objectivec/google/protobuf/Type.pbobjc.m1
-rw-r--r--objectivec/google/protobuf/Wrappers.pbobjc.h2
-rw-r--r--objectivec/google/protobuf/Wrappers.pbobjc.m1
30 files changed, 495 insertions, 12 deletions
diff --git a/objectivec/DevTools/compile_testing_protos.sh b/objectivec/DevTools/compile_testing_protos.sh
index 35a85046..6cc32da9 100755
--- a/objectivec/DevTools/compile_testing_protos.sh
+++ b/objectivec/DevTools/compile_testing_protos.sh
@@ -93,6 +93,7 @@ compile_protos() {
# sources can be generated from them.
CORE_PROTO_FILES=(
+ src/google/protobuf/any_test.proto
src/google/protobuf/unittest_arena.proto
src/google/protobuf/unittest_custom_options.proto
src/google/protobuf/unittest_enormous_descriptor.proto
diff --git a/objectivec/GPBBootstrap.h b/objectivec/GPBBootstrap.h
index 2e5bdc71..7dc943d4 100644
--- a/objectivec/GPBBootstrap.h
+++ b/objectivec/GPBBootstrap.h
@@ -99,4 +99,4 @@
// regenerated.
//
// Meant to be used internally by generated code.
-#define GOOGLE_PROTOBUF_OBJC_GEN_VERSION 30001
+#define GOOGLE_PROTOBUF_OBJC_GEN_VERSION 30002
diff --git a/objectivec/GPBDescriptor.h b/objectivec/GPBDescriptor.h
index 36fb4eae..651f4de0 100644
--- a/objectivec/GPBDescriptor.h
+++ b/objectivec/GPBDescriptor.h
@@ -81,6 +81,13 @@ typedef NS_ENUM(uint8_t, GPBFieldType) {
@property(nonatomic, readonly, getter=isWireFormat) BOOL wireFormat;
/** The class of this message. */
@property(nonatomic, readonly) Class messageClass;
+/** Containing message descriptor if this message is nested, or nil otherwise. */
+@property(readonly, nullable) GPBDescriptor *containingType;
+/**
+ * Fully qualified name for this message (package.message). Can be nil if the
+ * value is unable to be computed.
+ */
+@property(readonly, nullable) NSString *fullName;
/**
* Gets the field for the given number.
@@ -118,6 +125,8 @@ typedef NS_ENUM(uint8_t, GPBFieldType) {
/** The package declared in the proto file. */
@property(nonatomic, readonly, copy) NSString *package;
+/** The objc prefix declared in the proto file. */
+@property(nonatomic, readonly, copy, nullable) NSString *objcPrefix;
/** The syntax of the proto file. */
@property(nonatomic, readonly) GPBFileSyntax syntax;
diff --git a/objectivec/GPBDescriptor.m b/objectivec/GPBDescriptor.m
index dccb9bc8..0753a948 100644
--- a/objectivec/GPBDescriptor.m
+++ b/objectivec/GPBDescriptor.m
@@ -42,8 +42,10 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdirect-ivar-access"
-// The address of this variable is used as a key for obj_getAssociatedObject.
+// The addresses of these variables are used as keys for objc_getAssociatedObject.
static const char kTextFormatExtraValueKey = 0;
+static const char kParentClassNameValueKey = 0;
+static const char kClassNameSuffixKey = 0;
// Utility function to generate selectors on the fly.
static SEL SelFromStrings(const char *prefix, const char *middle,
@@ -215,10 +217,102 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex,
extensionRangesCount_ = count;
}
+- (void)setupContainingMessageClassName:(const char *)msgClassName {
+ // Note: Only fetch the class here, can't send messages to it because
+ // that could cause cycles back to this class within +initialize if
+ // two messages have each other in fields (i.e. - they build a graph).
+ NSAssert(objc_getClass(msgClassName), @"Class %s not defined", msgClassName);
+ NSValue *parentNameValue = [NSValue valueWithPointer:msgClassName];
+ objc_setAssociatedObject(self, &kParentClassNameValueKey,
+ parentNameValue,
+ OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (void)setupMessageClassNameSuffix:(NSString *)suffix {
+ if (suffix.length) {
+ objc_setAssociatedObject(self, &kClassNameSuffixKey,
+ suffix,
+ OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+ }
+}
+
- (NSString *)name {
return NSStringFromClass(messageClass_);
}
+- (GPBDescriptor *)containingType {
+ NSValue *parentNameValue =
+ objc_getAssociatedObject(self, &kParentClassNameValueKey);
+ if (!parentNameValue) {
+ return nil;
+ }
+ const char *parentName = [parentNameValue pointerValue];
+ Class parentClass = objc_getClass(parentName);
+ NSAssert(parentClass, @"Class %s not defined", parentName);
+ return [parentClass descriptor];
+}
+
+- (NSString *)fullName {
+ NSString *className = NSStringFromClass(self.messageClass);
+ GPBFileDescriptor *file = self.file;
+ NSString *objcPrefix = file.objcPrefix;
+ if (objcPrefix && ![className hasPrefix:objcPrefix]) {
+ NSAssert(0,
+ @"Class didn't have correct prefix? (%@ - %@)",
+ className, objcPrefix);
+ return nil;
+ }
+ GPBDescriptor *parent = self.containingType;
+
+ NSString *name = nil;
+ if (parent) {
+ NSString *parentClassName = NSStringFromClass(parent.messageClass);
+ // The generator will add _Class to avoid reserved words, drop it.
+ NSString *suffix = objc_getAssociatedObject(parent, &kClassNameSuffixKey);
+ if (suffix) {
+ if (![parentClassName hasSuffix:suffix]) {
+ NSAssert(0,
+ @"ParentMessage class didn't have correct suffix? (%@ - %@)",
+ className, suffix);
+ return nil;
+ }
+ parentClassName =
+ [parentClassName substringToIndex:(parentClassName.length - suffix.length)];
+ }
+ NSString *parentPrefix = [parentClassName stringByAppendingString:@"_"];
+ if (![className hasPrefix:parentPrefix]) {
+ NSAssert(0,
+ @"Class didn't have the correct parent name prefix? (%@ - %@)",
+ parentPrefix, className);
+ return nil;
+ }
+ name = [className substringFromIndex:parentPrefix.length];
+ } else {
+ name = [className substringFromIndex:objcPrefix.length];
+ }
+
+ // The generator will add _Class to avoid reserved words, drop it.
+ NSString *suffix = objc_getAssociatedObject(self, &kClassNameSuffixKey);
+ if (suffix) {
+ if (![name hasSuffix:suffix]) {
+ NSAssert(0,
+ @"Message class didn't have correct suffix? (%@ - %@)",
+ name, suffix);
+ return nil;
+ }
+ name = [name substringToIndex:(name.length - suffix.length)];
+ }
+
+ NSString *prefix = (parent != nil ? parent.fullName : file.package);
+ NSString *result;
+ if (prefix.length > 0) {
+ result = [NSString stringWithFormat:@"%@.%@", prefix, name];
+ } else {
+ result = name;
+ }
+ return result;
+}
+
- (id)copyWithZone:(NSZone *)zone {
#pragma unused(zone)
return [self retain];
@@ -255,13 +349,27 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex,
@implementation GPBFileDescriptor {
NSString *package_;
+ NSString *objcPrefix_;
GPBFileSyntax syntax_;
}
@synthesize package = package_;
+@synthesize objcPrefix = objcPrefix_;
@synthesize syntax = syntax_;
- (instancetype)initWithPackage:(NSString *)package
+ objcPrefix:(NSString *)objcPrefix
+ syntax:(GPBFileSyntax)syntax {
+ self = [super init];
+ if (self) {
+ package_ = [package copy];
+ objcPrefix_ = [objcPrefix copy];
+ syntax_ = syntax;
+ }
+ return self;
+}
+
+- (instancetype)initWithPackage:(NSString *)package
syntax:(GPBFileSyntax)syntax {
self = [super init];
if (self) {
@@ -273,6 +381,7 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex,
- (void)dealloc {
[package_ release];
+ [objcPrefix_ release];
[super dealloc];
}
@@ -416,6 +525,9 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
// Extra type specific data.
if (isMessage) {
const char *className = coreDesc->dataTypeSpecific.className;
+ // Note: Only fetch the class here, can't send messages to it because
+ // that could cause cycles back to this class within +initialize if
+ // two messages have each other in fields (i.e. - they build a graph).
msgClass_ = objc_getClass(className);
NSAssert(msgClass_, @"Class %s not defined", className);
} else if (dataType == GPBDataTypeEnum) {
diff --git a/objectivec/GPBDescriptor_PackagePrivate.h b/objectivec/GPBDescriptor_PackagePrivate.h
index c20ff6b0..66a4db77 100644
--- a/objectivec/GPBDescriptor_PackagePrivate.h
+++ b/objectivec/GPBDescriptor_PackagePrivate.h
@@ -165,11 +165,16 @@ typedef NS_OPTIONS(uint32_t, GPBDescriptorInitializationFlags) {
firstHasIndex:(int32_t)firstHasIndex;
- (void)setupExtraTextInfo:(const char *)extraTextFormatInfo;
- (void)setupExtensionRanges:(const GPBExtensionRange *)ranges count:(int32_t)count;
+- (void)setupContainingMessageClassName:(const char *)msgClassName;
+- (void)setupMessageClassNameSuffix:(NSString *)suffix;
@end
@interface GPBFileDescriptor ()
- (instancetype)initWithPackage:(NSString *)package
+ objcPrefix:(NSString *)objcPrefix
+ syntax:(GPBFileSyntax)syntax;
+- (instancetype)initWithPackage:(NSString *)package
syntax:(GPBFileSyntax)syntax;
@end
diff --git a/objectivec/GPBWellKnownTypes.h b/objectivec/GPBWellKnownTypes.h
index 96d51d9e..9ea57297 100644
--- a/objectivec/GPBWellKnownTypes.h
+++ b/objectivec/GPBWellKnownTypes.h
@@ -37,15 +37,32 @@
#endif
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
+ #import <Protobuf/Any.pbobjc.h>
#import <Protobuf/Duration.pbobjc.h>
#import <Protobuf/Timestamp.pbobjc.h>
#else
+ #import "google/protobuf/Any.pbobjc.h"
#import "google/protobuf/Duration.pbobjc.h"
#import "google/protobuf/Timestamp.pbobjc.h"
#endif
NS_ASSUME_NONNULL_BEGIN
+#pragma mark - Errors
+
+/** NSError domain used for errors. */
+extern NSString *const GPBWellKnownTypesErrorDomain;
+
+/** Error code for NSError with GPBWellKnownTypesErrorDomain. */
+typedef NS_ENUM(NSInteger, GPBWellKnownTypesErrorCode) {
+ /** The type_url could not be computed for the requested GPBMessage class. */
+ GPBWellKnownTypesErrorCodeFailedToComputeTypeURL = -100,
+ /** type_url in a Any doesn’t match that of the requested GPBMessage class. */
+ GPBWellKnownTypesErrorCodeTypeURLMismatch = -101,
+};
+
+#pragma mark - GPBTimestamp
+
/**
* Category for GPBTimestamp to work with standard Foundation time/date types.
**/
@@ -77,6 +94,8 @@ NS_ASSUME_NONNULL_BEGIN
@end
+#pragma mark - GPBDuration
+
/**
* Category for GPBDuration to work with standard Foundation time type.
**/
@@ -96,4 +115,110 @@ NS_ASSUME_NONNULL_BEGIN
@end
+#pragma mark - GPBAny
+
+/**
+ * Category for GPBAny to help work with the message within the object.
+ **/
+@interface GPBAny (GBPWellKnownTypes)
+
+/**
+ * Convenience method to create a GPBAny containing the serialized message.
+ * This uses type.googleapis.com/ as the type_url's prefix.
+ *
+ * @param message The message to be packed into the GPBAny.
+ * @param errorPtr Pointer to an error that will be populated if something goes
+ * wrong.
+ *
+ * @return A newly configured GPBAny with the given message, or nil on failure.
+ */
++ (nullable instancetype)anyWithMessage:(nonnull GPBMessage *)message
+ error:(NSError **)errorPtr;
+
+/**
+ * Convenience method to create a GPBAny containing the serialized message.
+ *
+ * @param message The message to be packed into the GPBAny.
+ * @param typeURLPrefix The URL prefix to apply for type_url.
+ * @param errorPtr Pointer to an error that will be populated if something
+ * goes wrong.
+ *
+ * @return A newly configured GPBAny with the given message, or nil on failure.
+ */
++ (nullable instancetype)anyWithMessage:(nonnull GPBMessage *)message
+ typeURLPrefix:(nonnull NSString *)typeURLPrefix
+ error:(NSError **)errorPtr;
+
+/**
+ * Initializes a GPBAny to contain the serialized message. This uses
+ * type.googleapis.com/ as the type_url's prefix.
+ *
+ * @param message The message to be packed into the GPBAny.
+ * @param errorPtr Pointer to an error that will be populated if something goes
+ * wrong.
+ *
+ * @return A newly configured GPBAny with the given message, or nil on failure.
+ */
+- (nullable instancetype)initWithMessage:(nonnull GPBMessage *)message
+ error:(NSError **)errorPtr;
+
+/**
+ * Initializes a GPBAny to contain the serialized message.
+ *
+ * @param message The message to be packed into the GPBAny.
+ * @param typeURLPrefix The URL prefix to apply for type_url.
+ * @param errorPtr Pointer to an error that will be populated if something
+ * goes wrong.
+ *
+ * @return A newly configured GPBAny with the given message, or nil on failure.
+ */
+- (nullable instancetype)initWithMessage:(nonnull GPBMessage *)message
+ typeURLPrefix:(nonnull NSString *)typeURLPrefix
+ error:(NSError **)errorPtr;
+
+/**
+ * Packs the serialized message into this GPBAny. This uses
+ * type.googleapis.com/ as the type_url's prefix.
+ *
+ * @param message The message to be packed into the GPBAny.
+ * @param errorPtr Pointer to an error that will be populated if something goes
+ * wrong.
+ *
+ * @return Whether the packing was successful or not.
+ */
+- (BOOL)packWithMessage:(nonnull GPBMessage *)message
+ error:(NSError **)errorPtr;
+
+/**
+ * Packs the serialized message into this GPBAny.
+ *
+ * @param message The message to be packed into the GPBAny.
+ * @param typeURLPrefix The URL prefix to apply for type_url.
+ * @param errorPtr Pointer to an error that will be populated if something
+ * goes wrong.
+ *
+ * @return Whether the packing was successful or not.
+ */
+- (BOOL)packWithMessage:(nonnull GPBMessage *)message
+ typeURLPrefix:(nonnull NSString *)typeURLPrefix
+ error:(NSError **)errorPtr;
+
+/**
+ * Unpacks the serialized message as if it was an instance of the given class.
+ *
+ * @note When checking type_url, the base URL is not checked, only the fully
+ * qualified name.
+ *
+ * @param messageClass The class to use to deserialize the contained message.
+ * @param errorPtr Pointer to an error that will be populated if something
+ * goes wrong.
+ *
+ * @return An instance of the given class populated with the contained data, or
+ * nil on failure.
+ */
+- (nullable GPBMessage *)unpackMessageClass:(Class)messageClass
+ error:(NSError **)errorPtr;
+
+@end
+
NS_ASSUME_NONNULL_END
diff --git a/objectivec/GPBWellKnownTypes.m b/objectivec/GPBWellKnownTypes.m
index 5cdd62d5..ed798a2e 100644
--- a/objectivec/GPBWellKnownTypes.m
+++ b/objectivec/GPBWellKnownTypes.m
@@ -34,6 +34,13 @@
#import "GPBWellKnownTypes.h"
+#import "GPBUtilities_PackagePrivate.h"
+
+NSString *const GPBWellKnownTypesErrorDomain =
+ GPBNSStringifySymbol(GPBWellKnownTypesErrorDomain);
+
+static NSString *kTypePrefixGoogleApisCom = @"type.googleapis.com/";
+
static NSTimeInterval TimeIntervalSince1970FromSecondsAndNanos(int64_t seconds,
int32_t nanos) {
return seconds + (NSTimeInterval)nanos / 1e9;
@@ -48,6 +55,30 @@ static int32_t SecondsAndNanosFromTimeIntervalSince1970(NSTimeInterval time,
return (int32_t)nanos;
}
+static NSString *BuildTypeURL(NSString *typeURLPrefix, NSString *fullName) {
+ if (typeURLPrefix.length == 0) {
+ return fullName;
+ }
+
+ if ([typeURLPrefix hasSuffix:@"/"]) {
+ return [typeURLPrefix stringByAppendingString:fullName];
+ }
+
+ return [NSString stringWithFormat:@"%@/%@", typeURLPrefix, fullName];
+}
+
+static NSString *ParseTypeFromURL(NSString *typeURLString) {
+ NSRange range = [typeURLString rangeOfString:@"/" options:NSBackwardsSearch];
+ if ((range.location == NSNotFound) ||
+ (NSMaxRange(range) == typeURLString.length)) {
+ return nil;
+ }
+ NSString *result = [typeURLString substringFromIndex:range.location + 1];
+ return result;
+}
+
+#pragma mark - GPBTimestamp
+
@implementation GPBTimestamp (GBPWellKnownTypes)
- (instancetype)initWithDate:(NSDate *)date {
@@ -87,6 +118,8 @@ static int32_t SecondsAndNanosFromTimeIntervalSince1970(NSTimeInterval time,
@end
+#pragma mark - GPBDuration
+
@implementation GPBDuration (GBPWellKnownTypes)
- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
@@ -113,3 +146,105 @@ static int32_t SecondsAndNanosFromTimeIntervalSince1970(NSTimeInterval time,
}
@end
+
+#pragma mark - GPBAny
+
+@implementation GPBAny (GBPWellKnownTypes)
+
++ (instancetype)anyWithMessage:(GPBMessage *)message
+ error:(NSError **)errorPtr {
+ return [self anyWithMessage:message
+ typeURLPrefix:kTypePrefixGoogleApisCom
+ error:errorPtr];
+}
+
++ (instancetype)anyWithMessage:(GPBMessage *)message
+ typeURLPrefix:(NSString *)typeURLPrefix
+ error:(NSError **)errorPtr {
+ return [[[self alloc] initWithMessage:message
+ typeURLPrefix:typeURLPrefix
+ error:errorPtr] autorelease];
+}
+
+- (instancetype)initWithMessage:(GPBMessage *)message
+ error:(NSError **)errorPtr {
+ return [self initWithMessage:message
+ typeURLPrefix:kTypePrefixGoogleApisCom
+ error:errorPtr];
+}
+
+- (instancetype)initWithMessage:(GPBMessage *)message
+ typeURLPrefix:(NSString *)typeURLPrefix
+ error:(NSError **)errorPtr {
+ self = [self init];
+ if (self) {
+ if (![self packWithMessage:message
+ typeURLPrefix:typeURLPrefix
+ error:errorPtr]) {
+ [self release];
+ self = nil;
+ }
+ }
+ return self;
+}
+
+- (BOOL)packWithMessage:(GPBMessage *)message
+ error:(NSError **)errorPtr {
+ return [self packWithMessage:message
+ typeURLPrefix:kTypePrefixGoogleApisCom
+ error:errorPtr];
+}
+
+- (BOOL)packWithMessage:(GPBMessage *)message
+ typeURLPrefix:(NSString *)typeURLPrefix
+ error:(NSError **)errorPtr {
+ NSString *fullName = [message descriptor].fullName;
+ if (fullName.length == 0) {
+ if (errorPtr) {
+ *errorPtr =
+ [NSError errorWithDomain:GPBWellKnownTypesErrorDomain
+ code:GPBWellKnownTypesErrorCodeFailedToComputeTypeURL
+ userInfo:nil];
+ }
+ return NO;
+ }
+ if (errorPtr) {
+ *errorPtr = nil;
+ }
+ self.typeURL = BuildTypeURL(typeURLPrefix, fullName);
+ self.value = message.data;
+ return YES;
+}
+
+- (GPBMessage *)unpackMessageClass:(Class)messageClass
+ error:(NSError **)errorPtr {
+ NSString *fullName = [messageClass descriptor].fullName;
+ if (fullName.length == 0) {
+ if (errorPtr) {
+ *errorPtr =
+ [NSError errorWithDomain:GPBWellKnownTypesErrorDomain
+ code:GPBWellKnownTypesErrorCodeFailedToComputeTypeURL
+ userInfo:nil];
+ }
+ return nil;
+ }
+
+ NSString *expectedFullName = ParseTypeFromURL(self.typeURL);
+ if ((expectedFullName == nil) || ![expectedFullName isEqual:fullName]) {
+ if (errorPtr) {
+ *errorPtr =
+ [NSError errorWithDomain:GPBWellKnownTypesErrorDomain
+ code:GPBWellKnownTypesErrorCodeTypeURLMismatch
+ userInfo:nil];
+ }
+ return nil;
+ }
+
+ // Any is proto3, which means no extensions, so this assumes anything put
+ // within an any also won't need extensions. A second helper could be added
+ // if needed.
+ return [messageClass parseFromData:self.value
+ error:errorPtr];
+}
+
+@end
diff --git a/objectivec/Tests/GPBDescriptorTests.m b/objectivec/Tests/GPBDescriptorTests.m
index 74e3172b..1e1c3de8 100644
--- a/objectivec/Tests/GPBDescriptorTests.m
+++ b/objectivec/Tests/GPBDescriptorTests.m
@@ -34,12 +34,41 @@
#import "GPBDescriptor.h"
#import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestObjc.pbobjc.h"
+#import "google/protobuf/Descriptor.pbobjc.h"
@interface DescriptorTests : GPBTestCase
@end
@implementation DescriptorTests
+- (void)testDescriptor_containingType {
+ GPBDescriptor *testAllTypesDesc = [TestAllTypes descriptor];
+ GPBDescriptor *nestedMessageDesc = [TestAllTypes_NestedMessage descriptor];
+ XCTAssertNil(testAllTypesDesc.containingType);
+ XCTAssertNotNil(nestedMessageDesc.containingType);
+ XCTAssertEqual(nestedMessageDesc.containingType, testAllTypesDesc); // Ptr comparison
+}
+
+- (void)testDescriptor_fullName {
+ GPBDescriptor *testAllTypesDesc = [TestAllTypes descriptor];
+ XCTAssertEqualObjects(testAllTypesDesc.fullName, @"protobuf_unittest.TestAllTypes");
+ GPBDescriptor *nestedMessageDesc = [TestAllTypes_NestedMessage descriptor];
+ XCTAssertEqualObjects(nestedMessageDesc.fullName, @"protobuf_unittest.TestAllTypes.NestedMessage");
+
+ // Prefixes removed.
+ GPBDescriptor *descDesc = [GPBDescriptorProto descriptor];
+ XCTAssertEqualObjects(descDesc.fullName, @"google.protobuf.DescriptorProto");
+ GPBDescriptor *descExtRngDesc = [GPBDescriptorProto_ExtensionRange descriptor];
+ XCTAssertEqualObjects(descExtRngDesc.fullName, @"google.protobuf.DescriptorProto.ExtensionRange");
+
+ // Things that get "_Class" added.
+ GPBDescriptor *pointDesc = [Point_Class descriptor];
+ XCTAssertEqualObjects(pointDesc.fullName, @"protobuf_unittest.Point");
+ GPBDescriptor *pointRectDesc = [Point_Rect descriptor];
+ XCTAssertEqualObjects(pointRectDesc.fullName, @"protobuf_unittest.Point.Rect");
+}
+
- (void)testFieldDescriptor {
GPBDescriptor *descriptor = [TestAllTypes descriptor];
diff --git a/objectivec/Tests/GPBUnittestProtos.m b/objectivec/Tests/GPBUnittestProtos.m
index 7b938e72..8d2948bf 100644
--- a/objectivec/Tests/GPBUnittestProtos.m
+++ b/objectivec/Tests/GPBUnittestProtos.m
@@ -36,6 +36,7 @@
// a descriptor as it doesn't use the classes/enums.
#import "google/protobuf/Descriptor.pbobjc.m"
+#import "google/protobuf/AnyTest.pbobjc.m"
#import "google/protobuf/MapProto2Unittest.pbobjc.m"
#import "google/protobuf/MapUnittest.pbobjc.m"
#import "google/protobuf/Unittest.pbobjc.m"
diff --git a/objectivec/Tests/GPBWellKnownTypesTest.m b/objectivec/Tests/GPBWellKnownTypesTest.m
index 78f4e637..041841dd 100644
--- a/objectivec/Tests/GPBWellKnownTypesTest.m
+++ b/objectivec/Tests/GPBWellKnownTypesTest.m
@@ -32,6 +32,8 @@
#import <XCTest/XCTest.h>
+#import "google/protobuf/AnyTest.pbobjc.h"
+
// A basically random interval into the future for testing with.
static const NSTimeInterval kFutureOffsetInterval = 15000;
@@ -99,4 +101,58 @@ static const NSTimeInterval kTimeAccuracy = 1e-9;
[duration2 release];
}
+- (void)testAnyHelpers {
+
+ // Set and extract covers most of the code.
+
+ TestAny *subMessage = [TestAny message];
+ subMessage.int32Value = 12345;
+ TestAny *message = [TestAny message];
+ NSError *err = nil;
+ message.anyValue = [GPBAny anyWithMessage:subMessage error:&err];
+ XCTAssertNil(err);
+
+ NSData *data = message.data;
+ XCTAssertNotNil(data);
+
+ TestAny *message2 = [TestAny parseFromData:data error:&err];
+ XCTAssertNil(err);
+ XCTAssertNotNil(message2);
+ XCTAssertTrue(message2.hasAnyValue);
+
+ TestAny *subMessage2 =
+ (TestAny *)[message.anyValue unpackMessageClass:[TestAny class]
+ error:&err];
+ XCTAssertNil(err);
+ XCTAssertNotNil(subMessage2);
+ XCTAssertEqual(subMessage2.int32Value, 12345);
+
+ // NULL errorPtr in the two calls.
+
+ message.anyValue = [GPBAny anyWithMessage:subMessage error:NULL];
+ NSData *data2 = message.data;
+ XCTAssertEqualObjects(data2, data);
+
+ TestAny *subMessage3 =
+ (TestAny *)[message.anyValue unpackMessageClass:[TestAny class]
+ error:NULL];
+ XCTAssertNotNil(subMessage3);
+ XCTAssertEqualObjects(subMessage2, subMessage3);
+
+ // Try to extract wrong type.
+
+ GPBTimestamp *wrongMessage =
+ (GPBTimestamp *)[message.anyValue unpackMessageClass:[GPBTimestamp class]
+ error:&err];
+ XCTAssertNotNil(err);
+ XCTAssertNil(wrongMessage);
+ XCTAssertEqualObjects(err.domain, GPBWellKnownTypesErrorDomain);
+ XCTAssertEqual(err.code, GPBWellKnownTypesErrorCodeTypeURLMismatch);
+
+ wrongMessage =
+ (GPBTimestamp *)[message.anyValue unpackMessageClass:[GPBTimestamp class]
+ error:NULL];
+ XCTAssertNil(wrongMessage);
+}
+
@end
diff --git a/objectivec/google/protobuf/Any.pbobjc.h b/objectivec/google/protobuf/Any.pbobjc.h
index 842052fe..b88b786a 100644
--- a/objectivec/google/protobuf/Any.pbobjc.h
+++ b/objectivec/google/protobuf/Any.pbobjc.h
@@ -13,7 +13,7 @@
#import "GPBProtocolBuffers.h"
#endif
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
diff --git a/objectivec/google/protobuf/Any.pbobjc.m b/objectivec/google/protobuf/Any.pbobjc.m
index deaedc16..50448cb1 100644
--- a/objectivec/google/protobuf/Any.pbobjc.m
+++ b/objectivec/google/protobuf/Any.pbobjc.m
@@ -41,6 +41,7 @@ static GPBFileDescriptor *GPBAnyRoot_FileDescriptor(void) {
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+ objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
}
return descriptor;
diff --git a/objectivec/google/protobuf/Api.pbobjc.h b/objectivec/google/protobuf/Api.pbobjc.h
index 182e866c..3750e093 100644
--- a/objectivec/google/protobuf/Api.pbobjc.h
+++ b/objectivec/google/protobuf/Api.pbobjc.h
@@ -13,7 +13,7 @@
#import "GPBProtocolBuffers.h"
#endif
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
diff --git a/objectivec/google/protobuf/Api.pbobjc.m b/objectivec/google/protobuf/Api.pbobjc.m
index e73ecf85..5736c818 100644
--- a/objectivec/google/protobuf/Api.pbobjc.m
+++ b/objectivec/google/protobuf/Api.pbobjc.m
@@ -45,6 +45,7 @@ static GPBFileDescriptor *GPBApiRoot_FileDescriptor(void) {
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+ objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
}
return descriptor;
diff --git a/objectivec/google/protobuf/Duration.pbobjc.h b/objectivec/google/protobuf/Duration.pbobjc.h
index fa91e223..090eb002 100644
--- a/objectivec/google/protobuf/Duration.pbobjc.h
+++ b/objectivec/google/protobuf/Duration.pbobjc.h
@@ -13,7 +13,7 @@
#import "GPBProtocolBuffers.h"
#endif
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
diff --git a/objectivec/google/protobuf/Duration.pbobjc.m b/objectivec/google/protobuf/Duration.pbobjc.m
index 79fbe007..70792768 100644
--- a/objectivec/google/protobuf/Duration.pbobjc.m
+++ b/objectivec/google/protobuf/Duration.pbobjc.m
@@ -41,6 +41,7 @@ static GPBFileDescriptor *GPBDurationRoot_FileDescriptor(void) {
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+ objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
}
return descriptor;
diff --git a/objectivec/google/protobuf/Empty.pbobjc.h b/objectivec/google/protobuf/Empty.pbobjc.h
index 4d36174d..e0ed3e16 100644
--- a/objectivec/google/protobuf/Empty.pbobjc.h
+++ b/objectivec/google/protobuf/Empty.pbobjc.h
@@ -13,7 +13,7 @@
#import "GPBProtocolBuffers.h"
#endif
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
diff --git a/objectivec/google/protobuf/Empty.pbobjc.m b/objectivec/google/protobuf/Empty.pbobjc.m
index 83cede25..f4f21f65 100644
--- a/objectivec/google/protobuf/Empty.pbobjc.m
+++ b/objectivec/google/protobuf/Empty.pbobjc.m
@@ -41,6 +41,7 @@ static GPBFileDescriptor *GPBEmptyRoot_FileDescriptor(void) {
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+ objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
}
return descriptor;
diff --git a/objectivec/google/protobuf/FieldMask.pbobjc.h b/objectivec/google/protobuf/FieldMask.pbobjc.h
index 491463f9..14ed5379 100644
--- a/objectivec/google/protobuf/FieldMask.pbobjc.h
+++ b/objectivec/google/protobuf/FieldMask.pbobjc.h
@@ -13,7 +13,7 @@
#import "GPBProtocolBuffers.h"
#endif
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
diff --git a/objectivec/google/protobuf/FieldMask.pbobjc.m b/objectivec/google/protobuf/FieldMask.pbobjc.m
index 906e3cbd..d4cceee9 100644
--- a/objectivec/google/protobuf/FieldMask.pbobjc.m
+++ b/objectivec/google/protobuf/FieldMask.pbobjc.m
@@ -41,6 +41,7 @@ static GPBFileDescriptor *GPBFieldMaskRoot_FileDescriptor(void) {
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+ objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
}
return descriptor;
diff --git a/objectivec/google/protobuf/SourceContext.pbobjc.h b/objectivec/google/protobuf/SourceContext.pbobjc.h
index d9450057..417562c0 100644
--- a/objectivec/google/protobuf/SourceContext.pbobjc.h
+++ b/objectivec/google/protobuf/SourceContext.pbobjc.h
@@ -13,7 +13,7 @@
#import "GPBProtocolBuffers.h"
#endif
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
diff --git a/objectivec/google/protobuf/SourceContext.pbobjc.m b/objectivec/google/protobuf/SourceContext.pbobjc.m
index 5c6ca6c0..d80231a5 100644
--- a/objectivec/google/protobuf/SourceContext.pbobjc.m
+++ b/objectivec/google/protobuf/SourceContext.pbobjc.m
@@ -41,6 +41,7 @@ static GPBFileDescriptor *GPBSourceContextRoot_FileDescriptor(void) {
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+ objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
}
return descriptor;
diff --git a/objectivec/google/protobuf/Struct.pbobjc.h b/objectivec/google/protobuf/Struct.pbobjc.h
index a5b31cd0..163b39ba 100644
--- a/objectivec/google/protobuf/Struct.pbobjc.h
+++ b/objectivec/google/protobuf/Struct.pbobjc.h
@@ -13,7 +13,7 @@
#import "GPBProtocolBuffers.h"
#endif
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
diff --git a/objectivec/google/protobuf/Struct.pbobjc.m b/objectivec/google/protobuf/Struct.pbobjc.m
index 55c135e6..02f7d24a 100644
--- a/objectivec/google/protobuf/Struct.pbobjc.m
+++ b/objectivec/google/protobuf/Struct.pbobjc.m
@@ -42,6 +42,7 @@ static GPBFileDescriptor *GPBStructRoot_FileDescriptor(void) {
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+ objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
}
return descriptor;
diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.h b/objectivec/google/protobuf/Timestamp.pbobjc.h
index ebfa670f..094e9b6b 100644
--- a/objectivec/google/protobuf/Timestamp.pbobjc.h
+++ b/objectivec/google/protobuf/Timestamp.pbobjc.h
@@ -13,7 +13,7 @@
#import "GPBProtocolBuffers.h"
#endif
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.m b/objectivec/google/protobuf/Timestamp.pbobjc.m
index 5e4d5cc1..7c57b4f5 100644
--- a/objectivec/google/protobuf/Timestamp.pbobjc.m
+++ b/objectivec/google/protobuf/Timestamp.pbobjc.m
@@ -41,6 +41,7 @@ static GPBFileDescriptor *GPBTimestampRoot_FileDescriptor(void) {
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+ objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
}
return descriptor;
diff --git a/objectivec/google/protobuf/Type.pbobjc.h b/objectivec/google/protobuf/Type.pbobjc.h
index 05411958..da923c30 100644
--- a/objectivec/google/protobuf/Type.pbobjc.h
+++ b/objectivec/google/protobuf/Type.pbobjc.h
@@ -13,7 +13,7 @@
#import "GPBProtocolBuffers.h"
#endif
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
diff --git a/objectivec/google/protobuf/Type.pbobjc.m b/objectivec/google/protobuf/Type.pbobjc.m
index b48f4d0f..dfe11860 100644
--- a/objectivec/google/protobuf/Type.pbobjc.m
+++ b/objectivec/google/protobuf/Type.pbobjc.m
@@ -45,6 +45,7 @@ static GPBFileDescriptor *GPBTypeRoot_FileDescriptor(void) {
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+ objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
}
return descriptor;
diff --git a/objectivec/google/protobuf/Wrappers.pbobjc.h b/objectivec/google/protobuf/Wrappers.pbobjc.h
index e397c480..2bf6fd29 100644
--- a/objectivec/google/protobuf/Wrappers.pbobjc.h
+++ b/objectivec/google/protobuf/Wrappers.pbobjc.h
@@ -13,7 +13,7 @@
#import "GPBProtocolBuffers.h"
#endif
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
diff --git a/objectivec/google/protobuf/Wrappers.pbobjc.m b/objectivec/google/protobuf/Wrappers.pbobjc.m
index ebf8e228..73a13842 100644
--- a/objectivec/google/protobuf/Wrappers.pbobjc.m
+++ b/objectivec/google/protobuf/Wrappers.pbobjc.m
@@ -41,6 +41,7 @@ static GPBFileDescriptor *GPBWrappersRoot_FileDescriptor(void) {
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+ objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
}
return descriptor;