THRIFT-3794 Split Delphi application, protocol and transport exception subtypes into separate exceptions
Client: Delphi
Patch: Kyle Johnson
diff --git a/lib/delphi/src/Thrift.pas b/lib/delphi/src/Thrift.pas
index 65f23ab..e969ebf 100644
--- a/lib/delphi/src/Thrift.pas
+++ b/lib/delphi/src/Thrift.pas
@@ -28,6 +28,8 @@
   Version = '1.0.0-dev';
 
 type
+  TApplicationExceptionSpecializedClass = class of TApplicationExceptionSpecialized;
+
   TApplicationException = class( SysUtils.Exception )
   public
     type
@@ -47,16 +49,40 @@
       );
 {$SCOPEDENUMS OFF}
   private
-    FType : TExceptionType;
+    function GetType: TExceptionType;
+  protected
+    constructor HiddenCreate(const Msg: string);
   public
-    constructor Create; overload;
-    constructor Create( AType: TExceptionType); overload;
-    constructor Create( AType: TExceptionType; const msg: string); overload;
+    // purposefully hide inherited constructor
+    class function Create(const Msg: string): TApplicationException; overload; deprecated 'Use specialized TApplicationException types (or regenerate from IDL)';
+    class function Create: TApplicationException; overload; deprecated 'Use specialized TApplicationException types (or regenerate from IDL)';
+    class function Create( AType: TExceptionType): TApplicationException; overload; deprecated 'Use specialized TApplicationException types (or regenerate from IDL)';
+    class function Create( AType: TExceptionType; const msg: string): TApplicationException; overload; deprecated 'Use specialized TApplicationException types (or regenerate from IDL)';
+
+    class function GetSpecializedExceptionType(AType: TExceptionType): TApplicationExceptionSpecializedClass;
 
     class function Read( const iprot: IProtocol): TApplicationException;
     procedure Write( const oprot: IProtocol );
   end;
 
+  // Needed to remove deprecation warning
+  TApplicationExceptionSpecialized = class abstract (TApplicationException)
+  public
+    constructor Create(const Msg: string);
+  end;
+
+  TApplicationExceptionUnknown = class (TApplicationExceptionSpecialized);
+  TApplicationExceptionUnknownMethod = class (TApplicationExceptionSpecialized);
+  TApplicationExceptionInvalidMessageType = class (TApplicationExceptionSpecialized);
+  TApplicationExceptionWrongMethodName = class (TApplicationExceptionSpecialized);
+  TApplicationExceptionBadSequenceID = class (TApplicationExceptionSpecialized);
+  TApplicationExceptionMissingResult = class (TApplicationExceptionSpecialized);
+  TApplicationExceptionInternalError = class (TApplicationExceptionSpecialized);
+  TApplicationExceptionProtocolError = class (TApplicationExceptionSpecialized);
+  TApplicationExceptionInvalidTransform = class (TApplicationExceptionSpecialized);
+  TApplicationExceptionInvalidProtocol = class (TApplicationExceptionSpecialized);
+  TApplicationExceptionUnsupportedClientType = class (TApplicationExceptionSpecialized);
+
   // base class for IDL-generated exceptions
   TException = class( SysUtils.Exception)
   public
@@ -84,22 +110,64 @@
 
 { TApplicationException }
 
-constructor TApplicationException.Create;
+function TApplicationException.GetType: TExceptionType;
 begin
-  inherited Create( '' );
+  if Self is TApplicationExceptionUnknownMethod then Result := TExceptionType.UnknownMethod
+  else if Self is TApplicationExceptionInvalidMessageType then Result := TExceptionType.InvalidMessageType
+  else if Self is TApplicationExceptionWrongMethodName then Result := TExceptionType.WrongMethodName
+  else if Self is TApplicationExceptionBadSequenceID then Result := TExceptionType.BadSequenceID
+  else if Self is TApplicationExceptionMissingResult then Result := TExceptionType.MissingResult
+  else if Self is TApplicationExceptionInternalError then Result := TExceptionType.InternalError
+  else if Self is TApplicationExceptionProtocolError then Result := TExceptionType.ProtocolError
+  else if Self is TApplicationExceptionInvalidTransform then Result := TExceptionType.InvalidTransform
+  else if Self is TApplicationExceptionInvalidProtocol then Result := TExceptionType.InvalidProtocol
+  else if Self is TApplicationExceptionUnsupportedClientType then Result := TExceptionType.UnsupportedClientType
+  else Result := TExceptionType.Unknown;
 end;
 
-constructor TApplicationException.Create(AType: TExceptionType;
-  const msg: string);
+constructor TApplicationException.HiddenCreate(const Msg: string);
 begin
-  inherited Create( msg );
-  FType := AType;
+  inherited Create(Msg);
 end;
 
-constructor TApplicationException.Create(AType: TExceptionType);
+class function TApplicationException.Create(const Msg: string): TApplicationException;
 begin
-  inherited Create('');
-  FType := AType;
+  Result := TApplicationExceptionUnknown.Create(Msg);
+end;
+
+class function TApplicationException.Create: TApplicationException;
+begin
+  Result := TApplicationExceptionUnknown.Create('');
+end;
+
+class function TApplicationException.Create( AType: TExceptionType): TApplicationException;
+begin
+{$WARN SYMBOL_DEPRECATED OFF}
+  Result := Create(AType, '');
+{$WARN SYMBOL_DEPRECATED DEFAULT}
+end;
+
+class function TApplicationException.Create( AType: TExceptionType; const msg: string): TApplicationException;
+begin
+  Result := GetSpecializedExceptionType(AType).Create(msg);
+end;
+
+class function TApplicationException.GetSpecializedExceptionType(AType: TExceptionType): TApplicationExceptionSpecializedClass;
+begin
+  case AType of
+    TExceptionType.UnknownMethod:         Result := TApplicationExceptionUnknownMethod;
+    TExceptionType.InvalidMessageType:    Result := TApplicationExceptionInvalidMessageType;
+    TExceptionType.WrongMethodName:       Result := TApplicationExceptionWrongMethodName;
+    TExceptionType.BadSequenceID:         Result := TApplicationExceptionBadSequenceID;
+    TExceptionType.MissingResult:         Result := TApplicationExceptionMissingResult;
+    TExceptionType.InternalError:         Result := TApplicationExceptionInternalError;
+    TExceptionType.ProtocolError:         Result := TApplicationExceptionProtocolError;
+    TExceptionType.InvalidTransform:      Result := TApplicationExceptionInvalidTransform;
+    TExceptionType.InvalidProtocol:       Result := TApplicationExceptionInvalidProtocol;
+    TExceptionType.UnsupportedClientType: Result := TApplicationExceptionUnsupportedClientType;
+  else
+    Result := TApplicationExceptionUnknown;
+  end;
 end;
 
 class function TApplicationException.Read( const iprot: IProtocol): TApplicationException;
@@ -147,7 +215,7 @@
     iprot.ReadFieldEnd;
   end;
   iprot.ReadStructEnd;
-  Result := TApplicationException.Create( typ, msg );
+  Result := GetSpecializedExceptionType(typ).Create(msg);
 end;
 
 procedure TApplicationException.Write( const oprot: IProtocol);
@@ -174,10 +242,17 @@
   field.Type_ := TType.I32;
   field.Id := 2;
   oprot.WriteFieldBegin(field);
-  oprot.WriteI32(Integer(FType));
+  oprot.WriteI32(Integer(GetType));
   oprot.WriteFieldEnd();
   oprot.WriteFieldStop();
   oprot.WriteStructEnd();
 end;
 
+{ TApplicationExceptionSpecialized }
+
+constructor TApplicationExceptionSpecialized.Create(const Msg: string);
+begin
+  inherited HiddenCreate(Msg);
+end;
+
 end.