[3743] | 1 | #region License Information
|
---|
| 2 | /* HeuristicLab
|
---|
[7259] | 3 | * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
|
---|
[3743] | 4 | *
|
---|
| 5 | * This file is part of HeuristicLab.
|
---|
| 6 | *
|
---|
| 7 | * HeuristicLab is free software: you can redistribute it and/or modify
|
---|
| 8 | * it under the terms of the GNU General Public License as published by
|
---|
| 9 | * the Free Software Foundation, either version 3 of the License, or
|
---|
| 10 | * (at your option) any later version.
|
---|
| 11 | *
|
---|
| 12 | * HeuristicLab is distributed in the hope that it will be useful,
|
---|
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
| 15 | * GNU General Public License for more details.
|
---|
| 16 | *
|
---|
| 17 | * You should have received a copy of the GNU General Public License
|
---|
| 18 | * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
|
---|
| 19 | */
|
---|
| 20 | #endregion
|
---|
| 21 |
|
---|
[1454] | 22 | using System;
|
---|
[1682] | 23 | using System.Reflection;
|
---|
[1823] | 24 | using HeuristicLab.Persistence.Core;
|
---|
[4068] | 25 | using HeuristicLab.Tracing;
|
---|
[1454] | 26 |
|
---|
[1823] | 27 | namespace HeuristicLab.Persistence.Auxiliary {
|
---|
[3004] | 28 | internal class TypeLoader {
|
---|
[8641] | 29 | public static Type Load(string typeNameString) {
|
---|
| 30 | try {
|
---|
| 31 | // try to load type normally
|
---|
| 32 | return LoadInternal(typeNameString);
|
---|
| 33 | }
|
---|
| 34 | catch (PersistenceException) {
|
---|
| 35 | #region Mono Compatibility
|
---|
| 36 | // if that fails, try to load Mono type
|
---|
| 37 | string monoTypeNameString = GetMonoType(typeNameString);
|
---|
| 38 | Logger.Info(String.Format(@"Trying to load Mono type ""{0}"" instead of type ""{1}""",
|
---|
| 39 | monoTypeNameString, typeNameString));
|
---|
| 40 | return LoadInternal(monoTypeNameString);
|
---|
| 41 | }
|
---|
| 42 | #endregion
|
---|
| 43 | }
|
---|
[1780] | 44 |
|
---|
[8641] | 45 | private static Type LoadInternal(string typeNameString) {
|
---|
[1780] | 46 | Type type;
|
---|
| 47 | try {
|
---|
| 48 | type = Type.GetType(typeNameString, true);
|
---|
[8641] | 49 | #region Mono Compatibility
|
---|
| 50 | // mono: workaround until Mono bug #580 (http://bugzilla.xamarin.com/show_bug.cgi?id=580) is fixed
|
---|
| 51 | if (type.AssemblyQualifiedName != typeNameString)
|
---|
| 52 | throw new TypeLoadException(
|
---|
| 53 | String.Format(
|
---|
| 54 | @"Could not load requested type ""{0}"", loaded ""{1}"" instead.",
|
---|
| 55 | typeNameString, type.AssemblyQualifiedName));
|
---|
| 56 | #endregion
|
---|
[4068] | 57 | }
|
---|
| 58 | catch (Exception) {
|
---|
[1780] | 59 | Logger.Warn(String.Format(
|
---|
[1795] | 60 | "Cannot load type \"{0}\", falling back to partial name", typeNameString));
|
---|
[8641] | 61 | type = LoadWithPartialName(typeNameString);
|
---|
| 62 | CheckCompatibility(typeNameString, type);
|
---|
| 63 | }
|
---|
| 64 | return type;
|
---|
| 65 | }
|
---|
| 66 |
|
---|
| 67 | private static Type LoadWithPartialName(string typeNameString) {
|
---|
| 68 | try {
|
---|
| 69 | TypeName typeName = TypeNameParser.Parse(typeNameString);
|
---|
[3036] | 70 | #pragma warning disable 0618
|
---|
[8641] | 71 | Assembly a = Assembly.LoadWithPartialName(typeName.AssemblyName);
|
---|
| 72 | // the suggested Assembly.Load() method fails to load assemblies outside the GAC
|
---|
[3036] | 73 | #pragma warning restore 0618
|
---|
[8641] | 74 | return a.GetType(typeName.ToString(false, false), true);
|
---|
| 75 | }
|
---|
| 76 | catch (Exception) {
|
---|
| 77 | throw new PersistenceException(String.Format(
|
---|
| 78 | "Could not load type \"{0}\"",
|
---|
| 79 | typeNameString));
|
---|
| 80 | }
|
---|
| 81 | }
|
---|
| 82 |
|
---|
| 83 | private static void CheckCompatibility(string typeNameString, Type type) {
|
---|
| 84 | try {
|
---|
| 85 | TypeName requestedTypeName = TypeNameParser.Parse(typeNameString);
|
---|
| 86 | TypeName loadedTypeName = TypeNameParser.Parse(type.AssemblyQualifiedName);
|
---|
| 87 | if (!requestedTypeName.IsCompatible(loadedTypeName))
|
---|
[1780] | 88 | throw new PersistenceException(String.Format(
|
---|
[8641] | 89 | "Serialized type is incompatible with available type: serialized: {0}, loaded: {1}",
|
---|
[1780] | 90 | typeNameString,
|
---|
[8641] | 91 | type.AssemblyQualifiedName));
|
---|
| 92 | if (requestedTypeName.IsNewerThan(loadedTypeName))
|
---|
| 93 | throw new PersistenceException(String.Format(
|
---|
| 94 | "Serialized type is newer than available type: serialized: {0}, loaded: {1}",
|
---|
| 95 | typeNameString,
|
---|
| 96 | type.AssemblyQualifiedName));
|
---|
[1780] | 97 | }
|
---|
[8641] | 98 | catch (PersistenceException) {
|
---|
| 99 | throw;
|
---|
| 100 | }
|
---|
| 101 | catch (Exception e) {
|
---|
| 102 | Logger.Warn(String.Format(
|
---|
| 103 | "Could not perform version check requested type was {0} while loaded type is {1}:",
|
---|
| 104 | typeNameString,
|
---|
| 105 | type.AssemblyQualifiedName),
|
---|
| 106 | e);
|
---|
| 107 | }
|
---|
[1780] | 108 | }
|
---|
[8641] | 109 |
|
---|
| 110 | #region Mono Compatibility
|
---|
| 111 | /// <summary>
|
---|
| 112 | /// Returns the corresponding type for the Mono runtime
|
---|
| 113 | /// </summary>
|
---|
| 114 | /// <returns>
|
---|
| 115 | /// The remapped typeNameString, or the original string if no mapping was found
|
---|
| 116 | /// </returns>
|
---|
| 117 | private static string GetMonoType(string typeNameString) {
|
---|
| 118 | TypeName typeName = TypeNameParser.Parse(typeNameString);
|
---|
| 119 |
|
---|
| 120 | // map System.RuntimeType to System.MonoType
|
---|
| 121 | if (typeName.Namespace == "System" && typeName.ClassName == "RuntimeType") {
|
---|
| 122 | // we use Int32 here because we get all the information about Mono's mscorlib and just have to change the class name
|
---|
| 123 | typeName = TypeNameParser.Parse(typeof(System.Int32).AssemblyQualifiedName);
|
---|
| 124 | typeName.ClassName = "MonoType";
|
---|
| 125 | } else if (typeName.Namespace == "System.Collections.Generic" && typeName.ClassName == "ObjectEqualityComparer") {
|
---|
| 126 | // map System.Collections.Generic.ObjectEqualityComparer to HeuristicLab.Mono.ObjectEqualityComparer
|
---|
| 127 | // we need the information about the Persistence assembly, so we use TypeName here because it is contained in this assembly
|
---|
| 128 | TypeName oecInfo = TypeNameParser.Parse(typeof(TypeName).AssemblyQualifiedName);
|
---|
| 129 | typeName.Namespace = "HeuristicLab.Persistence.Mono";
|
---|
| 130 | typeName.AssemblyName = oecInfo.AssemblyName;
|
---|
| 131 | typeName.AssemblyAttribues.Clear();
|
---|
| 132 | typeName.AssemblyAttribues["Version"] = oecInfo.AssemblyAttribues["Version"];
|
---|
| 133 | typeName.AssemblyAttribues["Culture"] = oecInfo.AssemblyAttribues["Culture"];
|
---|
| 134 | typeName.AssemblyAttribues["PublicKeyToken"] = oecInfo.AssemblyAttribues["PublicKeyToken"];
|
---|
| 135 | }
|
---|
| 136 |
|
---|
| 137 | return typeName.ToString(true, true);
|
---|
| 138 | }
|
---|
| 139 | #endregion
|
---|
[1780] | 140 | }
|
---|
[1454] | 141 | } |
---|