Click here to Skip to main content
15,881,089 members
Articles / Programming Languages / Markdown

APJSON

Rate me:
Please Sign up or sign in to vote.
4.67/5 (5 votes)
28 Aug 2013CPOL13 min read 41.6K   1.2K   34  
This is an alternative for "fastJSON"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Runtime.Serialization;

namespace Apolyton.FastJson.Registry
{
    /// <summary>
    /// Represents a class which describes a type by some unique naming methodology.
    /// </summary>
    public class JsonTypeDescriptor
    {
        private readonly RegistrySection<Type, string> _typeNameCache;
        private readonly RegistrySection<string, Type> _typeCache;

        /// <summary>
        /// Creates an instance of the type descriptor dictionary.
        /// </summary>
        public JsonTypeDescriptor()
        {
            _typeNameCache = new RegistrySection<Type, string>();
            _typeCache = new RegistrySection<string, Type>();

            Initialize();
        }

        #region Internals

        /// <summary>
        /// Returns the name of the type.
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        /// <exception cref="SerializationException">If the type does not have a proper name.</exception>
        internal String GetTypeName(Type type)
        {
            string val = "";

            if (_typeNameCache.TryGetValue(type, out val))
            {
                return val;
            }
            else
            {
                string s = CreateTypeName(type);

                if (String.IsNullOrEmpty(s))
                {
                    throw new SerializationException(String.Format("TypeDescriptor cannot return create a name for type '{0}' (value was empty)", type));
                }

                _typeNameCache.Add(type, s);

                return s;
            }
        }

        /// <summary>
        /// Returns the type for the given name.
        /// </summary>
        /// <param name="typeName"></param>
        /// <returns></returns>
        /// <exception cref="ApplicationException">If the type name could not be resolved into a proper name.</exception>
        internal Type GetType(String typeName)
        {
            Type val = null;
            if (_typeCache.TryGetValue(typeName, out val))
            {
                return val;
            }
            else
            {
                Type t = ResolveType(typeName);

                VerifyType(t, typeName);

                _typeCache.Add(typeName, t);
                return t;
            }
        }

        /// <summary>
        /// Tries to return the type for the given name.
        /// </summary>
        /// <param name="typeName"></param>
        /// <returns></returns>
        /// <exception cref="ApplicationException">If the type name could not be resolved into a proper name.</exception>
        internal bool TryGetType(String typeName, out Type type)
        {
            if (String.IsNullOrEmpty(typeName)) 
            { 
                type = null; 
                return false; 
            }

            if (_typeCache.TryGetValue(typeName, out type))
            {
                return true;
            }
            else
            {
                type = ResolveType(typeName);

                if (type != null)
                {
                    VerifyType(type, typeName);

                    _typeCache.Add(typeName, type);
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// Verifies that the resolved type is within expectations or throws an exception.
        /// </summary>
        /// <param name="t"></param>
        private static void VerifyType(Type type, String typeName)
        {
            if (type == null)
            {
                throw new SerializationException(String.Format("TypeDescriptor could not resolve the type with name '{0}'.", typeName));
            }

            // This is only relevant, if we deserialize. On client side however, the class might not be abstract anymore.
            //if (type.IsAbstract)
            //{
            //    throw new SerializationException(String.Format("The type '{0}' is abstract which is not acceptable since it cannot be constructed. (name was '{1}')", type, typeName));
            //}

#if SILVERLIGHT
            if (!type.IsPublic)
            {
                throw new SerializationException(String.Format("The type '{0}' is a non-public type. It must be public for deserialization purposes. (name was '{1}')", type, typeName));
            }
#endif

            // This is only relevant for deserialization...
            //var defaultConstructor = type.GetConstructor(Type.EmptyTypes);

            //if (defaultConstructor == null)
            //{
            //    throw new ApplicationException(String.Format("The type '{0}' is not offering a public default constructor which is mandatory.", type));
            //}
        }

        /// <summary>
        /// Registers an explicit type mapping.
        /// </summary>
        /// <param name="type"></param>
        /// <param name="p"></param>
        internal void Register(Type type, string typeName)
        {
            VerifyType(type, typeName);

            _typeCache.Add(typeName, type);
            _typeNameCache.Add(type, typeName);
        }

        #endregion

        /// <summary>
        /// Initialize the type descriptor.
        /// </summary>
        protected virtual void Initialize()
        {
        }

        /// <summary>
        /// Returns the expected name for the given type. The result is cached.
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        protected virtual String CreateTypeName(Type type)
        {
            return type.AssemblyQualifiedName;
        }

        /// <summary>
        /// Returns the type for the given type name.
        /// </summary>
        /// <param name="typeName"></param>
        /// <returns></returns>
        protected virtual Type ResolveType(String typeName)
        {
            return Type.GetType(typeName);
        }

        /// <summary>
        /// Resets the descriptor.
        /// </summary>
        internal void Reset()
        {
            _typeNameCache.Clear();
            _typeCache.Clear();

            Initialize();
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions