mirror of
https://github.com/danieleteti/delphimvcframework.git
synced 2024-11-15 07:45:54 +01:00
Improved enum and set parameters handling in JSONRPC API
This commit is contained in:
parent
de6e7960d7
commit
f79f4722d9
@ -466,7 +466,7 @@ The current beta release is named 3.2.2-nitrogen. If you want to stay on the-edg
|
||||
|
||||
- ⚡New `TMVCRESTClient` implementation based on *Net components, the previous one was based on INDY Components (thanks to [João Antônio Duarte](https://github.com/joaoduarte19)).
|
||||
|
||||
- ⚡New! `MVCJSONRPCAllowGET` attribute allows a remote JSON-RPC published object, or a specific method, to be called using GET HTTP Verb as well as POST HTTP Verb. POST is always available, GET is available only if explicitly allowed. `IMVCJSONRPCExecutor` allows to specify which HTTP Verb to use when call the server JSON.RPC methods. The default verb can be injected in the constructor and each `ExecuteRequest`/`ExecuteNotification` allows to override od adhere to the instance default.
|
||||
- ⚡New! `MVCJSONRPCAllowGET` attribute allows a remote JSON-RPC published object, or a specific method, to be called using GET HTTP Verb as well as POST HTTP Verb. POST is always available, GET is available only if explicitly allowed. `IMVCJSONRPCExecutor` allows to specify which HTTP Verb to use when call the server JSON-RPC methods. The default verb can be injected in the constructor and each `ExecuteRequest`/`ExecuteNotification` allows to override od adhere to the instance default.
|
||||
|
||||
- ⚡New! eLua server side view support added! The View engine requires Lua's dlls so it is not included in the main package but in a sampl project. Check `serversideviews_lua` sample.
|
||||
|
||||
@ -573,6 +573,8 @@ The current beta release is named 3.2.2-nitrogen. If you want to stay on the-edg
|
||||
|
||||
- ✅ Improved error handling for JSON-RPC APIs (Thanks to [David Moorhouse](https://github.com/fastbike)). More info [here](https://github.com/danieleteti/delphimvcframework/issues/538).
|
||||
|
||||
- ✅ Improved parameter handling for enum and set in JSON-RPC APIs.
|
||||
|
||||
- ⚡ New! Added `ActiveRecordConnectionRegistry.AddDefaultConnection(const aConnetionDefName: String)`. The connection definition **must** be known by FireDAC. This method simplifies the most common scenario shown below.
|
||||
|
||||
```delphi
|
||||
|
@ -38,6 +38,9 @@ uses
|
||||
|
||||
type
|
||||
|
||||
TEnumTest = (etValue1, etValue2, etValue3);
|
||||
TSetOfEnumTest = set of TEnumTest;
|
||||
|
||||
[MVCNameCase(ncLowerCase)]
|
||||
TPerson = class
|
||||
private
|
||||
|
@ -69,6 +69,9 @@ type
|
||||
procedure RaiseCustomException;
|
||||
function RaiseGenericException(const ExceptionType: Integer): Integer;
|
||||
function SaveObjectWithJSON(const WithJSON: TJsonObject): TJsonObject;
|
||||
//enums and sets support
|
||||
function PassingEnums(Value1: TEnumTest; Value2: TEnumTest): TEnumTest;
|
||||
|
||||
//records support
|
||||
function SavePersonRec(PersonRec: TTestRec): TTestRec;
|
||||
function GetPeopleRecDynArray: TTestRecDynArray;
|
||||
@ -123,6 +126,18 @@ begin
|
||||
|
||||
end;
|
||||
|
||||
function TMyObject.PassingEnums(Value1, Value2: TEnumTest): TEnumTest;
|
||||
begin
|
||||
if Value1 = Value2 then
|
||||
begin
|
||||
Result := TEnumTest.ptEnumValue4;
|
||||
end
|
||||
else
|
||||
begin
|
||||
Result := TEnumTest.ptEnumValue3;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TMyObject.EchoComplexArrayOfRecords(
|
||||
PeopleList: TTestRecDynArray): TTestRecDynArray;
|
||||
begin
|
||||
|
@ -29,6 +29,7 @@ var
|
||||
begin
|
||||
Writeln('** DMVCFramework Server ** build ' + DMVCFRAMEWORK_VERSION);
|
||||
Writeln('JSON-RPC Server with Published Objects');
|
||||
Writeln('Listening on port ', APort);
|
||||
|
||||
LServer := TIdHTTPWebBrokerBridge.Create(nil);
|
||||
try
|
||||
|
@ -34,14 +34,13 @@ interface
|
||||
uses
|
||||
System.Classes,
|
||||
Data.DB,
|
||||
System.SysUtils,
|
||||
jsondataobjects,
|
||||
MVCFramework,
|
||||
MVCFramework.Commons,
|
||||
System.Rtti,
|
||||
System.Generics.Collections,
|
||||
MVCFramework.Serializer.Commons,
|
||||
MVCFramework.Serializer.JsonDataObjects;
|
||||
MVCFramework.Serializer.JsonDataObjects, System.SysUtils;
|
||||
|
||||
const
|
||||
JSONRPC_VERSION = '2.0';
|
||||
@ -878,6 +877,7 @@ begin
|
||||
end;
|
||||
|
||||
procedure JSONDataValueToTValueParamEx(
|
||||
const JSONSerializer: TMVCJsonDataObjectsSerializer;
|
||||
const JSONDataValue: TJsonDataValueHelper;
|
||||
const RTTIParameter: TRttiParameter;
|
||||
var ParamValue: TValue;
|
||||
@ -940,13 +940,34 @@ begin
|
||||
end;
|
||||
end
|
||||
end;
|
||||
tkSet:
|
||||
begin
|
||||
if JSONDataValue.Typ <> jdtString then
|
||||
begin
|
||||
RaiseDeSerializationError('Cannot deserialize type ' + RTTIParameter.ParamType.Name);
|
||||
end;
|
||||
I := StringToSet(
|
||||
RTTIParameter.ParamType.Handle,
|
||||
StringReplace(JSONDataValue.Value, ' ', '', [rfReplaceAll]));
|
||||
TValue.Make(I, RTTIParameter.ParamType.Handle, ParamValue);
|
||||
end;
|
||||
tkEnumeration:
|
||||
begin
|
||||
if JSONDataValue.Typ <> jdtBool then
|
||||
if JSONDataValue.Typ = jdtBool then
|
||||
begin
|
||||
raise EMVCJSONRPCInvalidRequest.Create(BuildDeclaration(RTTIParameter));
|
||||
ParamValue := JSONDataValue.BoolValue;
|
||||
end
|
||||
else
|
||||
begin
|
||||
JSONSerializer.ParseStringAsTValueUsingMetadata(
|
||||
JSONDataValue.Value,
|
||||
RTTIParameter.ParamType.Handle,
|
||||
'type ' + RTTIParameter.ParamType.Name,
|
||||
RTTIParameter.ParamType.GetAttributes,
|
||||
ParamValue
|
||||
);
|
||||
end;
|
||||
ParamValue := JSONDataValue.BoolValue;
|
||||
|
||||
end;
|
||||
tkInteger:
|
||||
begin
|
||||
@ -1594,6 +1615,18 @@ begin
|
||||
lJSONResp := CreateError(lReqID, E.JSONRPCErrorCode, E.Message, E.JSONRPCErrorData);
|
||||
LogE(Format('[JSON-RPC][CLS %s][ERR %d][MSG "%s"]', [E.ClassName, E.JSONRPCErrorCode, E.Message]));
|
||||
end;
|
||||
on ExDeSer: EMVCDeserializationException do
|
||||
begin
|
||||
ResponseStatus(400);
|
||||
lJSONResp := CreateError(lReqID, JSONRPC_ERR_INVALID_REQUEST, ExDeSer.Message, ExDeSer.DetailedMessage);
|
||||
LogE(Format('[JSON-RPC][CLS %s][ERR %d][MSG "%s"]', [ExDeSer.ClassName, JSONRPC_ERR_INVALID_REQUEST, ExDeSer.Message]));
|
||||
end;
|
||||
on ExSer: EMVCSerializationException do
|
||||
begin
|
||||
ResponseStatus(400);
|
||||
lJSONResp := CreateError(lReqID, JSONRPC_ERR_INTERNAL_ERROR, ExSer.Message, ExSer.DetailedMessage);
|
||||
LogE(Format('[JSON-RPC][CLS %s][ERR %d][MSG "%s"]', [ExSer.ClassName, JSONRPC_ERR_INTERNAL_ERROR, ExSer.Message]));
|
||||
end;
|
||||
on Ex: Exception do // use another name for exception variable, otherwise E is nil!!
|
||||
begin
|
||||
//lJSONResp := CreateError(lReqID, 0, Ex.Message);
|
||||
@ -1608,7 +1641,7 @@ begin
|
||||
try
|
||||
if not lExceptionHandled then
|
||||
begin
|
||||
lJSONResp := CreateError(lReqID, 0, Ex.Message);
|
||||
lJSONResp := CreateError(lReqID, 0, Ex.Message, Ex.ClassName);
|
||||
end
|
||||
else
|
||||
begin
|
||||
@ -1750,6 +1783,7 @@ begin
|
||||
for I := 0 to lJSONParams.Count - 1 do
|
||||
begin
|
||||
JSONDataValueToTValueParamEx(
|
||||
fSerializer,
|
||||
lJSONParams[I],
|
||||
lRTTIMethodParams[I],
|
||||
lParamsArray[I],
|
||||
@ -1765,6 +1799,7 @@ begin
|
||||
for I := 0 to lJSONNamedParams.Count - 1 do
|
||||
begin
|
||||
JSONDataValueToTValueParamEx(
|
||||
fSerializer,
|
||||
GetJsonDataValueHelper(lJSONNamedParams, lRTTIMethodParams[I].Name.ToLower),
|
||||
lRTTIMethodParams[I],
|
||||
lParamsArray[I],
|
||||
|
@ -443,6 +443,7 @@ function ObjectDict(const OwnsValues: Boolean = True): IMVCObjectDictionary;
|
||||
function GetPaginationMeta(const CurrPageNumber: UInt32; const CurrPageSize: UInt32;
|
||||
const DefaultPageSize: UInt32; const URITemplate: string): TMVCStringDictionary;
|
||||
procedure RaiseSerializationError(const Msg: string);
|
||||
procedure RaiseDeSerializationError(const Msg: string);
|
||||
|
||||
implementation
|
||||
|
||||
|
@ -70,6 +70,12 @@ type
|
||||
function TryMapNullableFloat(var Value: TValue; const JSONDataObject: TJsonObject;
|
||||
const AttribName: string): Boolean;
|
||||
public
|
||||
procedure ParseStringAsTValueUsingMetadata(
|
||||
const AStringValue: String;
|
||||
const DestinationTypeInfo: PTypeInfo;
|
||||
const ExceptionHintString: String;
|
||||
const AAttributes: TArray<TCustomAttribute>;
|
||||
var AValue: TValue);
|
||||
function JSONObjectToRecord<T: record >(const JSONObject: TJsonObject): T; overload;
|
||||
function StrToRecord<T: record >(const AJSONString: String): T;
|
||||
procedure JSONObjectToNestedRecordField(const JSONObject: TJsonObject; RecordFieldRTTIType: TRttiField;
|
||||
@ -1424,84 +1430,90 @@ begin
|
||||
|
||||
jdtString:
|
||||
begin
|
||||
lValueTypeInfo := AValue.TypeInfo;
|
||||
if (lValueTypeInfo = System.TypeInfo(TDate)) then
|
||||
AValue := TValue.From<TDate>(ISODateToDate(AJSONObject[APropertyName].Value))
|
||||
|
||||
else if (lValueTypeInfo = System.TypeInfo(TDateTime)) then
|
||||
AValue := TValue.From<TDateTime>(ISOTimeStampToDateTime(AJSONObject[APropertyName].Value))
|
||||
|
||||
else if (lValueTypeInfo = System.TypeInfo(TTime)) then
|
||||
AValue := TValue.From<TTime>(ISOTimeToTime(AJSONObject[APropertyName].Value))
|
||||
else if (AValue.Kind = tkRecord) and (lValueTypeInfo <> TypeInfo(TValue)) then { nullables }
|
||||
begin
|
||||
if lValueTypeInfo = TypeInfo(NullableString) then
|
||||
begin
|
||||
AValue := TValue.From<NullableString>(NullableString(AJSONObject[APropertyName].Value))
|
||||
end
|
||||
else if lValueTypeInfo = TypeInfo(NullableTDate) then
|
||||
begin
|
||||
AValue := TValue.From<NullableTDate>(NullableTDate(ISODateToDate(AJSONObject[APropertyName].Value)))
|
||||
end
|
||||
else if lValueTypeInfo = TypeInfo(NullableTDateTime) then
|
||||
begin
|
||||
AValue := TValue.From<NullableTDateTime>
|
||||
(NullableTDateTime(ISOTimeStampToDateTime(AJSONObject[APropertyName].Value)))
|
||||
end
|
||||
else if lValueTypeInfo = TypeInfo(NullableTTime) then
|
||||
begin
|
||||
AValue := TValue.From<NullableTTime>(NullableTTime(ISOTimeToTime(AJSONObject[APropertyName].Value)))
|
||||
end
|
||||
else if lValueTypeInfo = TypeInfo(NullableTGUID) then
|
||||
begin
|
||||
AValue := TValue.From<NullableTGUID>(TMVCGuidHelper.StringToGUIDEx(AJSONObject[APropertyName].Value));
|
||||
end
|
||||
else
|
||||
raise EMVCSerializationException.CreateFmt('Cannot deserialize property "%s" from string', [APropertyName]);
|
||||
end
|
||||
else if (AValue.Kind = tkEnumeration) then
|
||||
begin
|
||||
LEnumSerType := estEnumName;
|
||||
LEnumMappedValues := nil;
|
||||
if TMVCSerializerHelper.AttributeExists<MVCEnumSerializationAttribute>(ACustomAttributes, LEnumAsAttr) then
|
||||
begin
|
||||
LEnumSerType := LEnumAsAttr.SerializationType;
|
||||
LEnumMappedValues := LEnumAsAttr.MappedValues;
|
||||
end;
|
||||
|
||||
if LEnumSerType = estEnumName then
|
||||
begin
|
||||
TValue.Make(GetEnumValue(AValue.TypeInfo, AJSONObject[APropertyName].Value), AValue.TypeInfo, AValue)
|
||||
end
|
||||
else
|
||||
begin
|
||||
LMappedValueIndex := LEnumMappedValues.IndexOf(AJSONObject[APropertyName].Value);
|
||||
if LMappedValueIndex < 0 then
|
||||
raise EMVCSerializationException.CreateFmt('Cannot deserialize property "%s" from mapped values',
|
||||
[APropertyName]);
|
||||
|
||||
TValue.Make(GetEnumValue(AValue.TypeInfo, GetEnumName(AValue.TypeInfo, LMappedValueIndex)),
|
||||
AValue.TypeInfo, AValue)
|
||||
end;
|
||||
end
|
||||
else if (AValue.Kind = tkInteger) and (TryStrToInt(AJSONObject[APropertyName].Value, lOutInteger)) then
|
||||
begin
|
||||
AValue := lOutInteger;
|
||||
end
|
||||
else if (AValue.Kind = tkInt64) and (TryStrToInt64(AJSONObject[APropertyName].Value, lOutInteger64)) then
|
||||
begin
|
||||
AValue := lOutInteger64;
|
||||
end
|
||||
else if lValueTypeInfo.Kind = tkSet then
|
||||
begin
|
||||
lInt := StringToSet(AValue.TypeInfo, StringReplace(AJSONObject[APropertyName].Value, ' ', '',
|
||||
[rfReplaceAll]));
|
||||
TValue.Make(lInt, AValue.TypeInfo, AValue);
|
||||
end
|
||||
else
|
||||
begin
|
||||
AValue := TValue.From<string>(AJSONObject[APropertyName].Value);
|
||||
end;
|
||||
ParseStringAsTValueUsingMetadata(
|
||||
AJSONObject[APropertyName].Value,
|
||||
AValue.TypeInfo,
|
||||
'property ' + APropertyName,
|
||||
ACustomAttributes,
|
||||
AValue);
|
||||
// lValueTypeInfo := AValue.TypeInfo;
|
||||
// if (lValueTypeInfo = System.TypeInfo(TDate)) then
|
||||
// AValue := TValue.From<TDate>(ISODateToDate(AJSONObject[APropertyName].Value))
|
||||
//
|
||||
// else if (lValueTypeInfo = System.TypeInfo(TDateTime)) then
|
||||
// AValue := TValue.From<TDateTime>(ISOTimeStampToDateTime(AJSONObject[APropertyName].Value))
|
||||
//
|
||||
// else if (lValueTypeInfo = System.TypeInfo(TTime)) then
|
||||
// AValue := TValue.From<TTime>(ISOTimeToTime(AJSONObject[APropertyName].Value))
|
||||
// else if (AValue.Kind = tkRecord) and (lValueTypeInfo <> TypeInfo(TValue)) then { nullables }
|
||||
// begin
|
||||
// if lValueTypeInfo = TypeInfo(NullableString) then
|
||||
// begin
|
||||
// AValue := TValue.From<NullableString>(NullableString(AJSONObject[APropertyName].Value))
|
||||
// end
|
||||
// else if lValueTypeInfo = TypeInfo(NullableTDate) then
|
||||
// begin
|
||||
// AValue := TValue.From<NullableTDate>(NullableTDate(ISODateToDate(AJSONObject[APropertyName].Value)))
|
||||
// end
|
||||
// else if lValueTypeInfo = TypeInfo(NullableTDateTime) then
|
||||
// begin
|
||||
// AValue := TValue.From<NullableTDateTime>
|
||||
// (NullableTDateTime(ISOTimeStampToDateTime(AJSONObject[APropertyName].Value)))
|
||||
// end
|
||||
// else if lValueTypeInfo = TypeInfo(NullableTTime) then
|
||||
// begin
|
||||
// AValue := TValue.From<NullableTTime>(NullableTTime(ISOTimeToTime(AJSONObject[APropertyName].Value)))
|
||||
// end
|
||||
// else if lValueTypeInfo = TypeInfo(NullableTGUID) then
|
||||
// begin
|
||||
// AValue := TValue.From<NullableTGUID>(TMVCGuidHelper.StringToGUIDEx(AJSONObject[APropertyName].Value));
|
||||
// end
|
||||
// else
|
||||
// raise EMVCSerializationException.CreateFmt('Cannot deserialize property "%s" from string', [APropertyName]);
|
||||
// end
|
||||
// else if (AValue.Kind = tkEnumeration) then
|
||||
// begin
|
||||
// LEnumSerType := estEnumName;
|
||||
// LEnumMappedValues := nil;
|
||||
// if TMVCSerializerHelper.AttributeExists<MVCEnumSerializationAttribute>(ACustomAttributes, LEnumAsAttr) then
|
||||
// begin
|
||||
// LEnumSerType := LEnumAsAttr.SerializationType;
|
||||
// LEnumMappedValues := LEnumAsAttr.MappedValues;
|
||||
// end;
|
||||
//
|
||||
// if LEnumSerType = estEnumName then
|
||||
// begin
|
||||
// TValue.Make(GetEnumValue(AValue.TypeInfo, AJSONObject[APropertyName].Value), AValue.TypeInfo, AValue)
|
||||
// end
|
||||
// else
|
||||
// begin
|
||||
// LMappedValueIndex := LEnumMappedValues.IndexOf(AJSONObject[APropertyName].Value);
|
||||
// if LMappedValueIndex < 0 then
|
||||
// raise EMVCSerializationException.CreateFmt('Cannot deserialize property "%s" from mapped values',
|
||||
// [APropertyName]);
|
||||
//
|
||||
// TValue.Make(GetEnumValue(AValue.TypeInfo, GetEnumName(AValue.TypeInfo, LMappedValueIndex)),
|
||||
// AValue.TypeInfo, AValue)
|
||||
// end;
|
||||
// end
|
||||
// else if (AValue.Kind = tkInteger) and (TryStrToInt(AJSONObject[APropertyName].Value, lOutInteger)) then
|
||||
// begin
|
||||
// AValue := lOutInteger;
|
||||
// end
|
||||
// else if (AValue.Kind = tkInt64) and (TryStrToInt64(AJSONObject[APropertyName].Value, lOutInteger64)) then
|
||||
// begin
|
||||
// AValue := lOutInteger64;
|
||||
// end
|
||||
// else if lValueTypeInfo.Kind = tkSet then
|
||||
// begin
|
||||
// lInt := StringToSet(AValue.TypeInfo, StringReplace(AJSONObject[APropertyName].Value, ' ', '',
|
||||
// [rfReplaceAll]));
|
||||
// TValue.Make(lInt, AValue.TypeInfo, AValue);
|
||||
// end
|
||||
// else
|
||||
// begin
|
||||
// AValue := TValue.From<string>(AJSONObject[APropertyName].Value);
|
||||
// end;
|
||||
end;
|
||||
|
||||
jdtInt:
|
||||
@ -2760,6 +2772,109 @@ begin
|
||||
Result := Parse<TJDOJsonObject>(AString);
|
||||
end;
|
||||
|
||||
procedure TMVCJsonDataObjectsSerializer.ParseStringAsTValueUsingMetadata(
|
||||
const AStringValue: String;
|
||||
const DestinationTypeInfo: PTypeInfo;
|
||||
const ExceptionHintString: String;
|
||||
const AAttributes: TArray<TCustomAttribute>;
|
||||
var AValue: TValue);
|
||||
var
|
||||
lValueTypeInfo: PTypeInfo;
|
||||
LEnumSerType: TMVCEnumSerializationType;
|
||||
LEnumAsAttr: MVCEnumSerializationAttribute;
|
||||
LEnumMappedValues: TList<string>;
|
||||
LMappedValueIndex: Integer;
|
||||
lOutInteger: Integer;
|
||||
lOutInteger64: Int64;
|
||||
lInt: Integer;
|
||||
begin
|
||||
lValueTypeInfo := DestinationTypeInfo;
|
||||
if (lValueTypeInfo = System.TypeInfo(TDate)) then
|
||||
AValue := TValue.From<TDate>(ISODateToDate(AStringValue))
|
||||
|
||||
else if (lValueTypeInfo = System.TypeInfo(TDateTime)) then
|
||||
AValue := TValue.From<TDateTime>(ISOTimeStampToDateTime(AStringValue))
|
||||
|
||||
else if (lValueTypeInfo = System.TypeInfo(TTime)) then
|
||||
AValue := TValue.From<TTime>(ISOTimeToTime(AStringValue))
|
||||
else if (lValueTypeInfo.Kind = tkRecord) and (lValueTypeInfo <> TypeInfo(TValue)) then { nullables }
|
||||
begin
|
||||
if lValueTypeInfo = TypeInfo(NullableString) then
|
||||
begin
|
||||
AValue := TValue.From<NullableString>(NullableString(AStringValue))
|
||||
end
|
||||
else if lValueTypeInfo = TypeInfo(NullableTDate) then
|
||||
begin
|
||||
AValue := TValue.From<NullableTDate>(NullableTDate(ISODateToDate(AStringValue)))
|
||||
end
|
||||
else if lValueTypeInfo = TypeInfo(NullableTDateTime) then
|
||||
begin
|
||||
AValue := TValue.From<NullableTDateTime>
|
||||
(NullableTDateTime(ISOTimeStampToDateTime(AStringValue)))
|
||||
end
|
||||
else if lValueTypeInfo = TypeInfo(NullableTTime) then
|
||||
begin
|
||||
AValue := TValue.From<NullableTTime>(NullableTTime(ISOTimeToTime(AStringValue)))
|
||||
end
|
||||
else if lValueTypeInfo = TypeInfo(NullableTGUID) then
|
||||
begin
|
||||
AValue := TValue.From<NullableTGUID>(TMVCGuidHelper.StringToGUIDEx(AStringValue));
|
||||
end
|
||||
else
|
||||
begin
|
||||
raise EMVCSerializationException.CreateFmt('Cannot deserialize "%s" from string', [ExceptionHintString]);
|
||||
end;
|
||||
end
|
||||
else if (lValueTypeInfo.Kind = tkEnumeration) then
|
||||
begin
|
||||
LEnumSerType := estEnumName;
|
||||
LEnumMappedValues := nil;
|
||||
if TMVCSerializerHelper.AttributeExists<MVCEnumSerializationAttribute>(AAttributes, LEnumAsAttr) then
|
||||
begin
|
||||
LEnumSerType := LEnumAsAttr.SerializationType;
|
||||
LEnumMappedValues := LEnumAsAttr.MappedValues;
|
||||
end;
|
||||
|
||||
if LEnumSerType = estEnumName then
|
||||
begin
|
||||
lOutInteger := GetEnumValue(lValueTypeInfo, AStringValue);
|
||||
if lOutInteger = -1 then
|
||||
begin
|
||||
raise EMVCSerializationException.CreateFmt('Cannot deserialize "%s" from mapped values',
|
||||
[ExceptionHintString]);
|
||||
end;
|
||||
TValue.Make(lOutInteger, lValueTypeInfo, AValue)
|
||||
end
|
||||
else
|
||||
begin
|
||||
LMappedValueIndex := LEnumMappedValues.IndexOf(AStringValue);
|
||||
if LMappedValueIndex < 0 then
|
||||
raise EMVCSerializationException.CreateFmt('Cannot deserialize "%s" from mapped values',
|
||||
[ExceptionHintString]);
|
||||
|
||||
TValue.Make(GetEnumValue(lValueTypeInfo, GetEnumName(lValueTypeInfo, LMappedValueIndex)),
|
||||
lValueTypeInfo, AValue)
|
||||
end;
|
||||
end
|
||||
else if (lValueTypeInfo.Kind = tkInteger) and (TryStrToInt(AStringValue, lOutInteger)) then
|
||||
begin
|
||||
AValue := lOutInteger;
|
||||
end
|
||||
else if (lValueTypeInfo.Kind = tkInt64) and (TryStrToInt64(AStringValue, lOutInteger64)) then
|
||||
begin
|
||||
AValue := lOutInteger64;
|
||||
end
|
||||
else if lValueTypeInfo.Kind = tkSet then
|
||||
begin
|
||||
lInt := StringToSet(lValueTypeInfo, StringReplace(AStringValue, ' ', '', [rfReplaceAll]));
|
||||
TValue.Make(lInt, lValueTypeInfo, AValue);
|
||||
end
|
||||
else
|
||||
begin
|
||||
AValue := TValue.From<string>(AStringValue);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMVCJsonDataObjectsSerializer.RecordToJsonObject(const ARecord: Pointer; const ARecordTypeInfo: PTypeInfo;
|
||||
const AJSONObject: TJDOJsonObject; const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
|
||||
begin
|
||||
|
@ -29,17 +29,21 @@ interface
|
||||
uses
|
||||
MVCFramework.Serializer.Commons, JsonDataObjects, MVCFramework.DuckTyping;
|
||||
|
||||
|
||||
function NewJSONSerializer: IMVCJSONSerializer;
|
||||
function StrToJSONObject(const aString: String; ARaiseExceptionOnError: Boolean = False): TJsonObject;
|
||||
function StrToJSONArray(const aString: String; ARaiseExceptionOnError: Boolean = False): TJsonArray;
|
||||
function WrapAsList(const AObject: TObject; AOwnsObject: Boolean = False): IMVCList;
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
MVCFramework.Serializer.JsonDataObjects,
|
||||
MVCFramework.Commons,
|
||||
System.SysUtils;
|
||||
System.SysUtils,
|
||||
System.TypInfo;
|
||||
|
||||
function NewJSONSerializer: IMVCJSONSerializer;
|
||||
begin
|
||||
|
@ -320,7 +320,6 @@ type
|
||||
[Test]
|
||||
procedure TestRequestToNotFoundMethod;
|
||||
[Test]
|
||||
[Category('this')]
|
||||
procedure TestRequestWithParams_I_I_ret_I;
|
||||
[Test]
|
||||
procedure TestRequestWithNamedParams_I_I_ret_I;
|
||||
@ -370,6 +369,17 @@ type
|
||||
procedure TestRequest_Echo_ComplexRecords;
|
||||
[Test]
|
||||
procedure TestRequest_NoParams_DynamicArrayOfRecordAsResult;
|
||||
//enum tests
|
||||
[Test]
|
||||
procedure TestEnum;
|
||||
[Test]
|
||||
procedure TestInvalidEnum;
|
||||
//set tests
|
||||
[Test]
|
||||
procedure TestSet;
|
||||
[Test]
|
||||
procedure TestInvalidSet;
|
||||
|
||||
end;
|
||||
|
||||
[TestFixture]
|
||||
@ -382,6 +392,7 @@ type
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.TypInfo,
|
||||
System.Math,
|
||||
System.JSON,
|
||||
MVCFramework.Serializer.Defaults,
|
||||
@ -405,7 +416,7 @@ uses
|
||||
Vcl.Graphics
|
||||
{$ENDIF}
|
||||
, TestConstsU, MVCFramework.Tests.Serializer.Entities,
|
||||
MVCFramework.Logger, System.IOUtils;
|
||||
MVCFramework.Logger, System.IOUtils, MVCFramework.Utils;
|
||||
|
||||
function GetServer: string;
|
||||
begin
|
||||
@ -2634,12 +2645,22 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TJSONRPCServerTest.TestEnum;
|
||||
begin
|
||||
var lRequest1: IJSONRPCRequest := TJSONRPCRequest.Create(1234, 'ProcessEnums');
|
||||
lRequest1.Params.Add('etValue1');
|
||||
lRequest1.Params.Add('etValue2');
|
||||
var lResp := FExecutor2.ExecuteRequest(lRequest1);
|
||||
Assert.AreEqual(
|
||||
GetEnumValue(TypeInfo(TEnumTest), 'etValue2'),
|
||||
GetEnumValue(TypeInfo(TEnumTest), lResp.Result.AsString)
|
||||
);
|
||||
end;
|
||||
|
||||
procedure TJSONRPCServerTest.TestHooks;
|
||||
begin
|
||||
var
|
||||
lRequest1: IJSONRPCRequest := TJSONRPCRequest.Create(1234, 'request1');
|
||||
var
|
||||
lResp := FExecutor3.ExecuteRequest(lRequest1);
|
||||
var lRequest1: IJSONRPCRequest := TJSONRPCRequest.Create(1234, 'request1');
|
||||
var lResp := FExecutor3.ExecuteRequest(lRequest1);
|
||||
Assert.areEqual('OnBeforeRoutingHook|OnBeforeCallHook|OnAfterCallHook',
|
||||
FExecutor3.HTTPResponse.HeaderValue['x-history']);
|
||||
end;
|
||||
@ -2744,14 +2765,31 @@ end;
|
||||
|
||||
procedure TJSONRPCServerTest.TestHooksWhenOnBeforeRoutingHookRaisesError;
|
||||
begin
|
||||
var
|
||||
lRequest1: IJSONRPCRequest := TJSONRPCRequest.Create(1234, 'error_OnBeforeRoutingHook');
|
||||
var
|
||||
lResp := FExecutor3.ExecuteRequest(lRequest1);
|
||||
var lRequest1: IJSONRPCRequest := TJSONRPCRequest.Create(1234, 'error_OnBeforeRoutingHook');
|
||||
var lResp := FExecutor3.ExecuteRequest(lRequest1);
|
||||
Assert.isTrue(lResp.IsError, lResp.ToString(true));
|
||||
Assert.areEqual(lResp.Error.ErrMessage, 'error_OnBeforeRoutingHook');
|
||||
end;
|
||||
|
||||
procedure TJSONRPCServerTest.TestInvalidEnum;
|
||||
begin
|
||||
var lRequest1: IJSONRPCRequest := TJSONRPCRequest.Create(1234, 'ProcessEnums');
|
||||
lRequest1.Params.Add('etValue1');
|
||||
lRequest1.Params.Add('blabla'); //invalid enum value
|
||||
var lResp := FExecutor2.ExecuteRequest(lRequest1);
|
||||
Assert.IsTrue(lResp.IsError);
|
||||
end;
|
||||
|
||||
procedure TJSONRPCServerTest.TestInvalidSet;
|
||||
begin
|
||||
var lRequest1: IJSONRPCRequest := TJSONRPCRequest.Create(1234, 'ProcessSets');
|
||||
lRequest1.Params.Add('etValue1,blabla');
|
||||
lRequest1.Params.Add('etValue3');
|
||||
var lResp := FExecutor2.ExecuteRequest(lRequest1);
|
||||
var l := lResp.AsJSONString;
|
||||
Assert.IsTrue(lResp.IsError);
|
||||
end;
|
||||
|
||||
procedure TJSONRPCServerTest.TestNotificationWhichRaisesError;
|
||||
var
|
||||
lReq: IJSONRPCNotification;
|
||||
@ -3143,6 +3181,16 @@ begin
|
||||
Assert.areEqual('DanieleDanieleDanieleDaniele', lRPCResp.Result.AsString);
|
||||
end;
|
||||
|
||||
procedure TJSONRPCServerTest.TestSet;
|
||||
begin
|
||||
var lRequest1: IJSONRPCRequest := TJSONRPCRequest.Create(1234, 'ProcessSets');
|
||||
lRequest1.Params.Add('etValue1,etValue2');
|
||||
lRequest1.Params.Add('etValue3');
|
||||
var lResp := FExecutor2.ExecuteRequest(lRequest1);
|
||||
var l := lResp.AsJSONString;
|
||||
Assert.AreEqual('etValue1,etValue2,etValue3', lResp.Result.AsString);
|
||||
end;
|
||||
|
||||
{ TJSONRPCServerWithGETTest }
|
||||
|
||||
procedure TJSONRPCServerWithGETTest.InitExecutors;
|
||||
|
@ -44,6 +44,14 @@ type
|
||||
[MVCInheritable]
|
||||
function AddTimeToDateTime(aDateTime: TDateTime; aTime: TTime): TDateTime;
|
||||
|
||||
//enums support
|
||||
[MVCInheritable]
|
||||
function ProcessEnums(Value1: TEnumTest; Value2: TEnumTest): TEnumTest;
|
||||
|
||||
//sets support
|
||||
[MVCInheritable]
|
||||
function ProcessSets(Value1: TSetOfEnumTest; Value2: TEnumTest): TSetOfEnumTest;
|
||||
|
||||
//records support
|
||||
[MVCInheritable]
|
||||
function GetSingleRecord: TSimpleRecord;
|
||||
@ -222,6 +230,18 @@ begin
|
||||
Self.ClassName;
|
||||
end;
|
||||
|
||||
function TTestJSONRPCClass.ProcessEnums(Value1, Value2: TEnumTest): TEnumTest;
|
||||
begin
|
||||
Result := TEnumTest((Ord(Value1) + Ord(Value2)) mod 3);
|
||||
end;
|
||||
|
||||
function TTestJSONRPCClass.ProcessSets(Value1: TSetOfEnumTest;
|
||||
Value2: TEnumTest): TSetOfEnumTest;
|
||||
begin
|
||||
Include(Value1, Value2);
|
||||
Result := Value1;
|
||||
end;
|
||||
|
||||
function TTestJSONRPCClass.Subtract(Value1, Value2: Int64): Integer;
|
||||
begin
|
||||
Result := Value1 - Value2;
|
||||
|
Loading…
Reference in New Issue
Block a user