IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
Serialization.cs
Go to the documentation of this file.
1/*
2 Copyright (C) 2009-2011 Jeroen Frijters
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
19
20 Jeroen Frijters
21 jeroen@frijters.net
22
23*/
24using System;
25using System.Runtime.Serialization;
26using System.Security;
27
28#if IMPORTER
29using IKVM.Reflection;
32
33using Type = IKVM.Reflection.Type;
34#else
35using System.Reflection;
36using System.Reflection.Emit;
37#endif
38
39namespace IKVM.Runtime
40{
41
43 {
44
45 readonly RuntimeContext context;
46
47 CustomAttributeBuilder serializableAttribute;
48 CustomAttributeBuilder securityCriticalAttribute;
49 RuntimeJavaType typeOfISerializable;
50 RuntimeJavaType typeofIObjectreference;
51 RuntimeJavaType typeOfExternalizable;
52
58 {
59 this.context = context ?? throw new ArgumentNullException(nameof(context));
60 }
61
62 CustomAttributeBuilder SerializableAttribute => serializableAttribute ??= new CustomAttributeBuilder(context.Resolver.ResolveCoreType(typeof(SerializableAttribute).FullName).GetConstructor([]).AsReflection(), Array.Empty<object>());
63
64 CustomAttributeBuilder SecurityCriticalAttribute => securityCriticalAttribute ??= new CustomAttributeBuilder(context.Resolver.ResolveCoreType(typeof(SecurityCriticalAttribute).FullName).GetConstructor([]).AsReflection(), Array.Empty<object>());
65
66 RuntimeJavaType TypeOfISerializable => typeOfISerializable ??= context.ClassLoaderFactory.GetJavaTypeFromType(context.Resolver.ResolveCoreType(typeof(ISerializable).FullName).AsReflection());
67
68 RuntimeJavaType TypeOfIObjectReference => typeofIObjectreference ??= context.ClassLoaderFactory.GetJavaTypeFromType(context.Resolver.ResolveCoreType(typeof(IObjectReference).FullName).AsReflection());
69
70 RuntimeJavaType TypeOfExternalizable => typeOfExternalizable ??= context.ClassLoaderFactory.LoadClassCritical("java.io.Externalizable");
71
72 internal bool IsISerializable(RuntimeJavaType wrapper)
73 {
74 return wrapper == TypeOfISerializable;
75 }
76
77 bool IsSafeForAutomagicSerialization(RuntimeJavaType wrapper)
78 {
79 if (wrapper.TypeAsBaseType.IsSerializable)
80 return false;
81 else if (wrapper.IsSubTypeOf(TypeOfISerializable))
82 return false;
83 else if (wrapper.IsSubTypeOf(TypeOfIObjectReference))
84 return false;
85 else if (wrapper.GetMethod("GetObjectData", "(Lcli.System.Runtime.Serialization.SerializationInfo;Lcli.System.Runtime.Serialization.StreamingContext;)V", false) != null)
86 return false;
87 else if (wrapper.GetMethod("<init>", "(Lcli.System.Runtime.Serialization.SerializationInfo;Lcli.System.Runtime.Serialization.StreamingContext;)V", false) != null)
88 return false;
89 else
90 return true;
91 }
92
93 internal MethodBuilder AddAutomagicSerialization(RuntimeByteCodeJavaType wrapper, TypeBuilder typeBuilder)
94 {
95 MethodBuilder serializationCtor = null;
96 if ((wrapper.Modifiers & IKVM.Attributes.Modifiers.Enum) != 0)
97 {
98 MarkSerializable(typeBuilder);
99 }
100 else if (wrapper.IsSubTypeOf(wrapper.Context.JavaBase.TypeOfJavaIoSerializable) && IsSafeForAutomagicSerialization(wrapper))
101 {
102 if (wrapper.IsSubTypeOf(TypeOfExternalizable))
103 {
104 var ctor = wrapper.GetMethod("<init>", "()V", false);
105 if (ctor != null && ctor.IsPublic)
106 {
107 MarkSerializable(typeBuilder);
108 ctor.Link();
109
110 serializationCtor = AddConstructor(typeBuilder, ctor, null, true);
111 if (!wrapper.BaseTypeWrapper.IsSubTypeOf(wrapper.Context.JavaBase.TypeOfJavaIoSerializable))
112 {
113 AddGetObjectData(typeBuilder);
114 }
115 if (wrapper.BaseTypeWrapper.GetMethod("readResolve", "()Ljava.lang.Object;", true) != null)
116 {
117 RemoveReadResolve(typeBuilder);
118 }
119 }
120 }
121 else if (wrapper.BaseTypeWrapper.IsSubTypeOf(wrapper.Context.JavaBase.TypeOfJavaIoSerializable))
122 {
123 var baseCtor = wrapper.GetBaseSerializationConstructor();
124 if (baseCtor != null && (baseCtor.IsFamily || baseCtor.IsFamilyOrAssembly))
125 {
126 MarkSerializable(typeBuilder);
127 serializationCtor = AddConstructor(typeBuilder, null, baseCtor, false);
128 AddReadResolve(wrapper, typeBuilder);
129 }
130 }
131 else
132 {
133 var baseCtor = wrapper.BaseTypeWrapper.GetMethod("<init>", "()V", false);
134 if (baseCtor != null && baseCtor.IsAccessibleFrom(wrapper.BaseTypeWrapper, wrapper, wrapper))
135 {
136 MarkSerializable(typeBuilder);
137 AddGetObjectData(typeBuilder);
138#if IMPORTER
139 // because the base type can be a __WorkaroundBaseClass__, we may need to replace the constructor
140 baseCtor = ((RuntimeImportByteCodeJavaType)wrapper).ReplaceMethodWrapper(baseCtor);
141#endif
142 baseCtor.Link();
143 serializationCtor = AddConstructor(typeBuilder, baseCtor, null, true);
144 AddReadResolve(wrapper, typeBuilder);
145 }
146 }
147 }
148
149 return serializationCtor;
150 }
151
152 internal MethodBuilder AddAutomagicSerializationToWorkaroundBaseClass(TypeBuilder typeBuilderWorkaroundBaseClass, MethodBase baseCtor)
153 {
154 if (typeBuilderWorkaroundBaseClass.BaseType.IsSerializable)
155 {
156 typeBuilderWorkaroundBaseClass.SetCustomAttribute(SerializableAttribute);
157 if (baseCtor != null && (baseCtor.IsFamily || baseCtor.IsFamilyOrAssembly))
158 return AddConstructor(typeBuilderWorkaroundBaseClass, null, baseCtor, false);
159 }
160
161 return null;
162 }
163
164 internal void MarkSerializable(TypeBuilder tb)
165 {
166 tb.SetCustomAttribute(SerializableAttribute);
167 }
168
169 internal void AddGetObjectData(TypeBuilder tb)
170 {
171 var name = tb.IsSealed ? "System.Runtime.Serialization.ISerializable.GetObjectData" : "GetObjectData";
172 var attr = tb.IsSealed
173 ? MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Final
174 : MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.CheckAccessOnOverride;
175 tb.AddInterfaceImplementation(context.Resolver.ResolveCoreType(typeof(ISerializable).FullName).AsReflection());
176 var getObjectData = tb.DefineMethod(name, attr, null, new Type[] { context.Resolver.ResolveCoreType(typeof(SerializationInfo).FullName).AsReflection(), context.Resolver.ResolveCoreType(typeof(StreamingContext).FullName).AsReflection() });
177 getObjectData.SetCustomAttribute(SecurityCriticalAttribute);
178 context.AttributeHelper.HideFromJava(getObjectData);
179 tb.DefineMethodOverride(getObjectData, context.Resolver.ResolveCoreType(typeof(ISerializable).FullName).GetMethod("GetObjectData").AsReflection());
180 CodeEmitter ilgen = context.CodeEmitterFactory.Create(getObjectData);
181 ilgen.Emit(OpCodes.Ldarg_0);
182 ilgen.Emit(OpCodes.Ldarg_1);
183 RuntimeJavaType serializationHelper = context.ClassLoaderFactory.LoadClassCritical("ikvm.internal.Serialization");
184 RuntimeJavaMethod mw = serializationHelper.GetMethod("writeObject", "(Ljava.lang.Object;Lcli.System.Runtime.Serialization.SerializationInfo;)V", false);
185 mw.Link();
186 mw.EmitCall(ilgen);
187 ilgen.Emit(OpCodes.Ret);
188 ilgen.DoEmit();
189 }
190
191 MethodBuilder AddConstructor(TypeBuilder tb, RuntimeJavaMethod defaultConstructor, MethodBase serializationConstructor, bool callReadObject)
192 {
193 MethodBuilder ctor = ReflectUtil.DefineConstructor(tb, MethodAttributes.Family, new Type[] { context.Resolver.ResolveCoreType(typeof(SerializationInfo).FullName).AsReflection(), context.Resolver.ResolveCoreType(typeof(StreamingContext).FullName).AsReflection() });
194 context.AttributeHelper.HideFromJava(ctor);
195 CodeEmitter ilgen = context.CodeEmitterFactory.Create(ctor);
196 ilgen.Emit(OpCodes.Ldarg_0);
197 if (defaultConstructor != null)
198 {
199 defaultConstructor.EmitCall(ilgen);
200 }
201 else
202 {
203 ilgen.Emit(OpCodes.Ldarg_1);
204 ilgen.Emit(OpCodes.Ldarg_2);
205 ilgen.Emit(OpCodes.Call, serializationConstructor);
206 }
207 if (callReadObject)
208 {
209 ilgen.Emit(OpCodes.Ldarg_0);
210 ilgen.Emit(OpCodes.Ldarg_1);
211 RuntimeJavaType serializationHelper = context.ClassLoaderFactory.LoadClassCritical("ikvm.internal.Serialization");
212 RuntimeJavaMethod mw = serializationHelper.GetMethod("readObject", "(Ljava.lang.Object;Lcli.System.Runtime.Serialization.SerializationInfo;)V", false);
213 mw.Link();
214 mw.EmitCall(ilgen);
215 }
216 ilgen.Emit(OpCodes.Ret);
217 ilgen.DoEmit();
218 return ctor;
219 }
220
221 void AddReadResolve(RuntimeByteCodeJavaType wrapper, TypeBuilder tb)
222 {
223 var mw = wrapper.GetMethod("readResolve", "()Ljava.lang.Object;", false);
224 if (mw != null && !wrapper.IsSubTypeOf(TypeOfIObjectReference))
225 {
226 tb.AddInterfaceImplementation(wrapper.Context.Resolver.ResolveCoreType(typeof(IObjectReference).FullName).AsReflection());
227 var getRealObject = tb.DefineMethod("IObjectReference.GetRealObject", MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Final, wrapper.Context.Types.Object, new Type[] { wrapper.Context.Resolver.ResolveCoreType(typeof(StreamingContext).FullName).AsReflection() });
228 getRealObject.SetCustomAttribute(SecurityCriticalAttribute);
229 wrapper.Context.AttributeHelper.HideFromJava(getRealObject);
230 tb.DefineMethodOverride(getRealObject, wrapper.Context.Resolver.ResolveCoreType(typeof(IObjectReference).FullName).GetMethod("GetRealObject").AsReflection());
231 var ilgen = context.CodeEmitterFactory.Create(getRealObject);
232 mw.Link();
233 if (!wrapper.IsFinal)
234 {
235 // readResolve is only applicable if it exists on the actual type of the object, so if we're a subclass don't call it
236 ilgen.Emit(OpCodes.Ldarg_0);
237 ilgen.Emit(OpCodes.Callvirt, wrapper.Context.CompilerFactory.GetTypeMethod);
238 ilgen.Emit(OpCodes.Ldtoken, wrapper.TypeAsBaseType);
239 ilgen.Emit(OpCodes.Call, wrapper.Context.CompilerFactory.GetTypeFromHandleMethod);
240 CodeEmitterLabel label = ilgen.DefineLabel();
241 ilgen.EmitBeq(label);
242 ilgen.Emit(OpCodes.Ldarg_0);
243 ilgen.Emit(OpCodes.Ret);
244 ilgen.MarkLabel(label);
245 }
246 ilgen.Emit(OpCodes.Ldarg_0);
247 mw.EmitCall(ilgen);
248 ilgen.Emit(OpCodes.Ret);
249 ilgen.DoEmit();
250 }
251 }
252
253 void RemoveReadResolve(TypeBuilder tb)
254 {
255 tb.AddInterfaceImplementation(context.Resolver.ResolveCoreType(typeof(IObjectReference).FullName).AsReflection());
256 MethodBuilder getRealObject = tb.DefineMethod("IObjectReference.GetRealObject", MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Final, context.Types.Object, [context.Resolver.ResolveCoreType(typeof(StreamingContext).FullName).AsReflection()]);
257 getRealObject.SetCustomAttribute(SecurityCriticalAttribute);
258 context.AttributeHelper.HideFromJava(getRealObject);
259 tb.DefineMethodOverride(getRealObject, context.Resolver.ResolveCoreType(typeof(IObjectReference).FullName).GetMethod("GetRealObject").AsReflection());
260 CodeEmitter ilgen = context.CodeEmitterFactory.Create(getRealObject);
261 ilgen.Emit(OpCodes.Ldarg_0);
262 ilgen.Emit(OpCodes.Ret);
263 ilgen.DoEmit();
264 }
265
266 }
267
268}
IKVM.Reflection.Type Type
IKVM.Reflection.MethodBase MethodBase
Maintains services relevant to an instane of the IKVM runtime.
Serialization(RuntimeContext context)
Initializes a new instance.
Implementation of RuntimeByteCodeJavaType that customizes output for the importer.