| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "Cache.hpp" |
| #include "ReflectionBasedAutoSerializer.hpp" |
| #include "PdxIdentityFieldAttribute.hpp" |
| #include "Serializable.hpp" |
| #pragma warning(disable:4091) |
| #include <msclr/lock.h> |
| #include "ExceptionTypes.hpp" |
| #include "impl/DotNetTypes.hpp" |
| #include "TypeRegistry.hpp" |
| |
| namespace Apache |
| { |
| namespace Geode |
| { |
| namespace Client |
| { |
| |
| ref class FieldWrapper |
| { |
| private: |
| //static readonly Module Module = typeof(Program).Module; |
| static array<Type^>^ oneObj = gcnew array<Type^>(1) { Type::GetType("System.Object") }; |
| static array<Type^>^ twoObj = gcnew array<Type^>(2) { Type::GetType("System.Object"), Type::GetType("System.Object") }; |
| delegate void MySetter(Object^ t1, Object^ t2); |
| delegate Object^ MyGetter(Object^ t1); |
| |
| static Type^ setterDelegateType = Type::GetType("Apache.Geode.Client.FieldWrapper+MySetter"); |
| static Type^ getterDelegateType = Type::GetType("Apache.Geode.Client.FieldWrapper+MyGetter"); |
| |
| FieldInfo^ m_fi; |
| String^ m_fieldName; |
| bool m_isIdentityField; |
| FieldType m_fieldType; |
| int m_pdxType; |
| |
| MyGetter^ m_getter; |
| MySetter^ m_setter; |
| |
| static MySetter^ createFieldSetter(FieldInfo^ fieldInfo) |
| { |
| DynamicMethod^ dynam = gcnew DynamicMethod("", Internal::DotNetTypes::VoidType , twoObj, fieldInfo->DeclaringType, true); |
| ILGenerator^ il = dynam->GetILGenerator(); |
| |
| if (!fieldInfo->IsStatic) |
| pushInstance(il, fieldInfo->DeclaringType); |
| |
| il->Emit(OpCodes::Ldarg_1); |
| unboxIfNeeded(il, fieldInfo->FieldType); |
| il->Emit(OpCodes::Stfld, fieldInfo); |
| il->Emit(OpCodes::Ret); |
| |
| return (MySetter^)dynam->CreateDelegate( setterDelegateType ); |
| } |
| |
| static MyGetter^ createFieldGetter(FieldInfo^ fieldInfo) |
| { |
| DynamicMethod^ dynam = gcnew DynamicMethod( "", Internal::DotNetTypes::ObjectType, oneObj, fieldInfo->DeclaringType, true); |
| ILGenerator^ il = dynam->GetILGenerator(); |
| |
| if (!fieldInfo->IsStatic) |
| pushInstance(il, fieldInfo->DeclaringType); |
| |
| il->Emit(OpCodes::Ldfld, fieldInfo); |
| boxIfNeeded(il, fieldInfo->FieldType); |
| il->Emit(OpCodes::Ret); |
| |
| return (MyGetter^)dynam->CreateDelegate(getterDelegateType); |
| } |
| |
| static void boxIfNeeded(ILGenerator^ il, Type^ type) |
| { |
| if (type->IsValueType) |
| il->Emit(OpCodes::Box, type); |
| } |
| |
| static void pushInstance( ILGenerator^ il, Type^ type) |
| { |
| il->Emit(OpCodes::Ldarg_0); |
| if (type->IsValueType) |
| il->Emit(OpCodes::Unbox, type); |
| } |
| |
| static void unboxIfNeeded( ILGenerator^ il, Type^ type) |
| { |
| if (type->IsValueType) |
| il->Emit(OpCodes::Unbox_Any, type); |
| } |
| public: |
| FieldWrapper(FieldInfo^ fi, String^ fieldName, bool isIdentityField, FieldType fieldtype) |
| { |
| m_fi = fi; |
| m_fieldName = fieldName; |
| m_isIdentityField = isIdentityField; |
| m_fieldType = fieldtype; |
| |
| m_setter = createFieldSetter(fi); |
| m_getter = createFieldGetter(fi); |
| } |
| |
| property bool isIdentityField |
| { |
| bool get(){return m_isIdentityField;} |
| } |
| |
| property Type^ FType |
| { |
| Type^ get() {return m_fi->FieldType;} |
| } |
| |
| property String^ FieldName |
| { |
| String^ get(){return m_fieldName;} |
| } |
| |
| property FieldInfo^ FI |
| { |
| FieldInfo^ get(){return m_fi;} |
| } |
| |
| void SetFieldValue(Object^ parent, Object^ val) |
| { |
| m_setter(parent, val); |
| } |
| |
| Object^ GetFieldValue(Object^ parent) |
| { |
| return m_getter(parent); |
| } |
| |
| void SerializeField(IPdxWriter^ w, Object^ value) |
| { |
| switch(m_fieldType) |
| { |
| case FieldType::BOOLEAN: |
| w->WriteBoolean(m_fieldName, (bool)value); |
| break; |
| case FieldType::BYTE: |
| w->WriteByte(m_fieldName, (SByte)value); |
| break; |
| case FieldType::CHAR: |
| w->WriteChar(m_fieldName, (Char)value); |
| break; |
| case FieldType::SHORT: |
| w->WriteShort(m_fieldName, (short)value); |
| break; |
| case FieldType::INT: |
| w->WriteInt(m_fieldName, (int)value); |
| break; |
| case FieldType::LONG: |
| w->WriteLong(m_fieldName, (Int64)value); |
| break; |
| case FieldType::FLOAT: |
| w->WriteFloat(m_fieldName, (float)value); |
| break; |
| case FieldType::DOUBLE: |
| w->WriteDouble(m_fieldName, (double)value); |
| break; |
| case FieldType::DATE: |
| w->WriteDate(m_fieldName, (DateTime)value); |
| break; |
| case FieldType::STRING: |
| w->WriteString(m_fieldName, (String^)value); |
| break; |
| case FieldType::OBJECT: |
| w->WriteObject(m_fieldName, value); |
| break; |
| case FieldType::BOOLEAN_ARRAY: |
| w->WriteBooleanArray(m_fieldName, (array<bool>^)value); |
| break; |
| case FieldType::CHAR_ARRAY: |
| w->WriteCharArray(m_fieldName, (array<Char>^)value); |
| break; |
| case FieldType::BYTE_ARRAY: |
| w->WriteByteArray(m_fieldName, (array<Byte>^)value); |
| break; |
| case FieldType::SHORT_ARRAY: |
| w->WriteShortArray(m_fieldName, (array<Int16>^)value); |
| break; |
| case FieldType::INT_ARRAY: |
| w->WriteIntArray(m_fieldName, (array<Int32>^)value); |
| break; |
| case FieldType::LONG_ARRAY: |
| w->WriteLongArray(m_fieldName, (array<System::Int64>^)value); |
| break; |
| case FieldType::FLOAT_ARRAY: |
| w->WriteFloatArray(m_fieldName, (array<float>^)value); |
| break; |
| case FieldType::DOUBLE_ARRAY: |
| w->WriteDoubleArray(m_fieldName, (array<double>^)value); |
| break; |
| case FieldType::STRING_ARRAY: |
| w->WriteStringArray(m_fieldName, (array<String^>^)value); |
| break; |
| case FieldType::OBJECT_ARRAY: |
| w->WriteObjectArray(m_fieldName, safe_cast<System::Collections::Generic::List<Object^>^>(value)); |
| break; |
| case FieldType::ARRAY_OF_BYTE_ARRAYS: |
| w->WriteArrayOfByteArrays(m_fieldName, (array<array<Byte>^>^)value); |
| break; |
| default: |
| throw gcnew IllegalStateException("Not found FieldType: " + m_fieldType.ToString()); |
| } |
| } |
| |
| Object^ DeserializeField(IPdxReader^ r) |
| { |
| switch(m_fieldType) |
| { |
| case FieldType::BOOLEAN: |
| return r->ReadBoolean(m_fieldName); |
| break; |
| case FieldType::BYTE: |
| return r->ReadByte(m_fieldName); |
| break; |
| case FieldType::CHAR: |
| return r->ReadChar(m_fieldName); |
| break; |
| case FieldType::SHORT: |
| return r->ReadShort(m_fieldName); |
| break; |
| case FieldType::INT: |
| return r->ReadInt(m_fieldName); |
| break; |
| case FieldType::LONG: |
| return r->ReadLong(m_fieldName); |
| break; |
| case FieldType::FLOAT: |
| return r->ReadFloat(m_fieldName); |
| break; |
| case FieldType::DOUBLE: |
| return r->ReadDouble(m_fieldName); |
| break; |
| case FieldType::DATE: |
| return r->ReadDate(m_fieldName); |
| break; |
| case FieldType::STRING: |
| return r->ReadString(m_fieldName); |
| break; |
| case FieldType::OBJECT: |
| return r->ReadObject(m_fieldName); |
| break; |
| case FieldType::BOOLEAN_ARRAY: |
| return r->ReadBooleanArray(m_fieldName); |
| break; |
| case FieldType::CHAR_ARRAY: |
| return r->ReadCharArray(m_fieldName); |
| break; |
| case FieldType::BYTE_ARRAY: |
| return r->ReadByteArray(m_fieldName); |
| break; |
| case FieldType::SHORT_ARRAY: |
| return r->ReadShortArray(m_fieldName); |
| break; |
| case FieldType::INT_ARRAY: |
| return r->ReadIntArray(m_fieldName); |
| break; |
| case FieldType::LONG_ARRAY: |
| return r->ReadLongArray(m_fieldName); |
| break; |
| case FieldType::FLOAT_ARRAY: |
| return r->ReadFloatArray(m_fieldName); |
| break; |
| case FieldType::DOUBLE_ARRAY: |
| return r->ReadDoubleArray(m_fieldName); |
| break; |
| case FieldType::STRING_ARRAY: |
| return r->ReadStringArray(m_fieldName); |
| break; |
| case FieldType::OBJECT_ARRAY: |
| return r->ReadObjectArray(m_fieldName); |
| break; |
| case FieldType::ARRAY_OF_BYTE_ARRAYS: |
| return r->ReadArrayOfByteArrays(m_fieldName); |
| break; |
| default: |
| throw gcnew IllegalStateException("Not found FieldType: " + m_fieldType.ToString()); |
| } |
| return nullptr; |
| } |
| |
| |
| |
| }; |
| |
| ReflectionBasedAutoSerializer::ReflectionBasedAutoSerializer() |
| { |
| PdxIdentityFieldAttribute^ pif = gcnew PdxIdentityFieldAttribute(); |
| PdxIdentityFieldAttributeType = pif->GetType(); |
| classNameVsFieldInfoWrapper = gcnew Dictionary<String^, List<FieldWrapper^>^>(); |
| } |
| |
| bool ReflectionBasedAutoSerializer::ToData( Object^ o,IPdxWriter^ writer ) |
| { |
| serializeFields(o, writer); |
| return true; |
| } |
| |
| Object^ ReflectionBasedAutoSerializer::FromData(String^ o, IPdxReader^ reader) |
| { |
| return deserializeFields(o, reader); |
| } |
| |
| void ReflectionBasedAutoSerializer::serializeFields(Object^ o,IPdxWriter^ writer ) |
| { |
| Type^ ty = o->GetType(); |
| // Log::Debug("ReflectionBasedAutoSerializer::serializeFields classname {0}: objectType {1}", o->GetType()->FullName,o->GetType()); |
| for each(FieldWrapper^ fi in GetFields(o->GetType())) |
| { |
| // Log::Debug("ReflectionBasedAutoSerializer::serializeFields fieldName: {0}, fieldType: {1}", fi->FieldName, fi->FType); |
| // writer->WriteField(fi->Name, fi->GetValue(o), fi->FieldType); |
| // SerializeField(o, fi, writer); |
| //Object^ originalValue = fi->FI->GetValue(o); |
| Object^ originalValue = fi->GetFieldValue(o); |
| //hook which can overide by app |
| originalValue = WriteTransform(fi->FI, fi->FType, originalValue); |
| |
| fi->SerializeField(writer, originalValue); |
| |
| if(fi->isIdentityField) |
| { |
| // Log::Debug("ReflectionBasedAutoSerializer::serializeFields fieldName: {0} is identity field.", fi->FieldName); |
| writer->MarkIdentityField(fi->FieldName); |
| } |
| } |
| |
| // serializeBaseClassFields(o, writer, ty->BaseType); |
| } |
| |
| Object^ ReflectionBasedAutoSerializer::deserializeFields(String^ className, IPdxReader^ reader) |
| { |
| Object^ object = this->CreateObject(className, reader->Cache); |
| |
| for each(FieldWrapper^ fi in GetFields(object->GetType())) |
| { |
| Object^ serializeValue = fi->DeserializeField(reader); |
| serializeValue = ReadTransform( fi->FI, fi->FType, serializeValue); |
| fi->SetFieldValue(object, serializeValue); |
| } |
| |
| return object; |
| } |
| |
| Object^ ReflectionBasedAutoSerializer::CreateObject(String^ className, Cache^ cache) |
| { |
| return cache->TypeRegistry->CreateObject(className); |
| } |
| |
| bool ReflectionBasedAutoSerializer::IsPdxIdentityField(FieldInfo^ fi) |
| { |
| array<Object^>^ cAttr= fi->GetCustomAttributes(PdxIdentityFieldAttributeType, true); |
| if(cAttr != nullptr && cAttr->Length > 0) |
| { |
| PdxIdentityFieldAttribute^ pifa = (PdxIdentityFieldAttribute^)(cAttr[0]); |
| return true; |
| } |
| return false; |
| } |
| |
| List<FieldWrapper^>^ ReflectionBasedAutoSerializer::GetFields(Type^ domaimType) |
| { |
| List<FieldWrapper^>^ retVal = nullptr; |
| |
| String^ className = domaimType->FullName; |
| System::Collections::Generic::Dictionary<String^, List<FieldWrapper^>^>^ tmp = classNameVsFieldInfoWrapper; |
| tmp->TryGetValue(className, retVal); |
| if(retVal != nullptr) |
| return retVal; |
| msclr::lock lockInstance(classNameVsFieldInfoWrapper); |
| { |
| tmp = classNameVsFieldInfoWrapper; |
| tmp->TryGetValue(className, retVal); |
| if(retVal != nullptr) |
| return retVal; |
| |
| List<FieldWrapper^>^ collectFields = gcnew List<FieldWrapper^>(); |
| while(domaimType != nullptr) |
| { |
| for each(FieldInfo^ fi in domaimType->GetFields(BindingFlags::Public| BindingFlags::NonPublic | BindingFlags::Instance |
| |BindingFlags::DeclaredOnly |
| )) |
| { |
| if(!fi->IsNotSerialized && !fi->IsStatic && !fi->IsLiteral && !fi->IsInitOnly) |
| { |
| //to ignore the fild |
| if(IsFieldIncluded(fi, domaimType)) |
| { |
| //This are all hooks which app can implement |
| |
| String^ fieldName = GetFieldName(fi, domaimType); |
| bool isIdentityField = IsIdentityField(fi, domaimType); |
| FieldType ft = GetFieldType(fi, domaimType); |
| |
| FieldWrapper^ fw = gcnew FieldWrapper(fi, fieldName, isIdentityField, ft); |
| |
| collectFields->Add(fw); |
| } |
| } |
| } |
| domaimType = domaimType->BaseType; |
| } |
| tmp = gcnew System::Collections::Generic::Dictionary<String^, List<FieldWrapper^>^>(classNameVsFieldInfoWrapper); |
| tmp->Add(className, collectFields); |
| classNameVsFieldInfoWrapper = tmp; |
| |
| return collectFields; |
| } |
| } |
| |
| |
| String^ ReflectionBasedAutoSerializer::GetFieldName(FieldInfo^ fi, Type^ type) |
| { |
| return fi->Name; |
| } |
| |
| bool ReflectionBasedAutoSerializer::IsIdentityField(FieldInfo^ fi, Type^ type) |
| { |
| return IsPdxIdentityField(fi); |
| } |
| |
| FieldType ReflectionBasedAutoSerializer::GetFieldType(FieldInfo^ fi, Type^ type) |
| { |
| return getPdxFieldType(fi->FieldType); |
| } |
| |
| bool ReflectionBasedAutoSerializer::IsFieldIncluded(FieldInfo^ fi, Type^ type) |
| { |
| return true; |
| } |
| |
| Object^ ReflectionBasedAutoSerializer::WriteTransform(FieldInfo^ fi, Type^ type, Object^ originalValue) |
| { |
| return originalValue; |
| } |
| |
| Object^ ReflectionBasedAutoSerializer::ReadTransform(FieldInfo^ fi, Type^ type, Object^ serializeValue) |
| { |
| return serializeValue; |
| } |
| |
| FieldType ReflectionBasedAutoSerializer::getPdxFieldType( Type^ type) |
| { |
| if(type->Equals(Internal::DotNetTypes::IntType)) |
| { |
| return FieldType::INT; |
| } |
| else if(type->Equals(Internal::DotNetTypes::StringType)) |
| { |
| return FieldType::STRING; |
| } |
| else if(type->Equals(Internal::DotNetTypes::BooleanType)) |
| { |
| return FieldType::BOOLEAN; |
| } |
| else if(type->Equals(Internal::DotNetTypes::FloatType)) |
| { |
| return FieldType::FLOAT; |
| } |
| else if(type->Equals(Internal::DotNetTypes::DoubleType)) |
| { |
| return FieldType::DOUBLE; |
| } |
| else if(type->Equals(Internal::DotNetTypes::CharType)) |
| { |
| return FieldType::CHAR; |
| } |
| else if(type->Equals(Internal::DotNetTypes::SByteType)) |
| { |
| return FieldType::BYTE; |
| } |
| else if(type->Equals(Internal::DotNetTypes::ShortType)) |
| { |
| return FieldType::SHORT; |
| } |
| else if(type->Equals(Internal::DotNetTypes::LongType)) |
| { |
| return FieldType::LONG; |
| } |
| else if(type->Equals(Internal::DotNetTypes::ByteArrayType)) |
| { |
| return FieldType::BYTE_ARRAY; |
| } |
| else if(type->Equals(Internal::DotNetTypes::DoubleArrayType)) |
| { |
| return FieldType::DOUBLE_ARRAY; |
| } |
| else if(type->Equals(Internal::DotNetTypes::FloatArrayType)) |
| { |
| return FieldType::FLOAT_ARRAY; |
| } |
| else if(type->Equals(Internal::DotNetTypes::ShortArrayType)) |
| { |
| return FieldType::SHORT_ARRAY; |
| } |
| else if(type->Equals(Internal::DotNetTypes::IntArrayType)) |
| { |
| return FieldType::INT_ARRAY; |
| } |
| else if(type->Equals(Internal::DotNetTypes::LongArrayType)) |
| { |
| return FieldType::LONG_ARRAY; |
| } |
| else if(type->Equals(Internal::DotNetTypes::BoolArrayType)) |
| { |
| return FieldType::BOOLEAN_ARRAY; |
| } |
| else if(type->Equals(Internal::DotNetTypes::CharArrayType)) |
| { |
| return FieldType::CHAR_ARRAY; |
| } |
| else if(type->Equals(Internal::DotNetTypes::StringArrayType)) |
| { |
| return FieldType::STRING_ARRAY; |
| } |
| else if(type->Equals(Internal::DotNetTypes::DateType)) |
| { |
| return FieldType::DATE; |
| } |
| else if(type->Equals(Internal::DotNetTypes::ByteArrayOfArrayType)) |
| { |
| return FieldType::ARRAY_OF_BYTE_ARRAYS; |
| } |
| /*else if(type->Equals(Internal::DotNetTypes::ObjectArrayType)) |
| { |
| //Giving more preference to arraylist instead of Object[] in java side |
| //return this->WriteObjectArray(fieldName, safe_cast<System::Collections::Generic::List<Object^>^>(fieldValue)); |
| return FieldType::OBJECT_ARRAY; |
| }*/ |
| else |
| { |
| return FieldType::OBJECT; |
| //throw gcnew IllegalStateException("WriteField unable to serialize " |
| // + fieldName + " of " + type); |
| } // namespace Client |
| } // namespace Geode |
| } // namespace Apache |
| |
| } |
| } |