Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Excluding some properties during serialization without changing the original class

I'm trying to serialize an object with several properties, but I don't want to include all properties in the serialization. Also, I would like to change the date format.

Of course I could add [XmlIgnore], but I'm not allowed to change the original class.

The only option I could think of was to create a new class and copy all contents between the two classes. But that would be ugly and would require a lot of manual code.

Would it maybe be possible to maybe create a subclass, since the original is not abstract?

My question is thus:

  1. How can I exclude some properties without changing the original class?

  2. How can I customize the date format of the output XML?

Requirements:

  1. As strong typed as possible

  2. Serialized XML should be deserializable

Thanks in advance.

like image 908
Schiavini Avatar asked Feb 21 '12 12:02

Schiavini


People also ask

How do you ignore property serializable?

WhenWritingDefault - The property is ignored on serialization if it's a reference type null , a nullable value type null , or a value type default . WhenWritingNull - The property is ignored on serialization if it's a reference type null , or a nullable value type null .

Which one of the following keyword we can exclude some object properties from serialization process?

Use the @XmlTransient annotation: Prevents the mapping of a JavaBean property/type to XML representation.

What is the name of the attribute that excludes a class property from serialization?

Transient is the Java way to exclude from serialization, then our field will also be filtered out by Serializable's serialization, and by every library tool or framework managing our objects.

How do you prevent a variable from being serialized in a serializable class?

You can prevent member variables from being serialized by marking them with the NonSerialized attribute as follows. If possible, make an object that could contain security-sensitive data nonserializable. If the object must be serialized, apply the NonSerialized attribute to specific fields that store sensitive data.


2 Answers

For whoever is interested, I decided to use XmlAttributeOverrides, but made them more strong typed (I hate to type property names as strings). Here is the extension method I used for it:

    public static void Add<T>(this XmlAttributeOverrides overrides, Expression<Func<T, dynamic>> propertySelector, XmlAttributes attributes)
    {
        overrides.Add(typeof(T), propertySelector.BuildString(), attributes);
    }

    public static string BuildString(this Expression propertySelector)
    {
        switch (propertySelector.NodeType)
        {
            case ExpressionType.Lambda:
                LambdaExpression lambdaExpression = (LambdaExpression)propertySelector;
                return BuildString(lambdaExpression.Body);

            case ExpressionType.Convert:
            case ExpressionType.Quote:
                UnaryExpression unaryExpression = (UnaryExpression)propertySelector;
                return BuildString(unaryExpression.Operand);

            case ExpressionType.MemberAccess:

                MemberExpression memberExpression = (MemberExpression)propertySelector;
                MemberInfo propertyInfo = memberExpression.Member;

                if (memberExpression.Expression is ParameterExpression)
                {
                    return propertyInfo.Name;
                }
                else
                {
                    // we've got a nested property (e.g. MyType.SomeProperty.SomeNestedProperty)
                    return BuildString(memberExpression.Expression) + "." + propertyInfo.Name;
                }

            default:
                // drop out and throw
                break;
        }
        throw new InvalidOperationException("Expression must be a member expression: " + propertySelector.ToString());
    }

Then, to ignore an attribute, I can beautifully add it to the ignore list:

    var overrides = new XmlAttributeOverrides();
    var ignore = new XmlAttributes { XmlIgnore = true };
    overrides.Add<MyClass>(m => m.Id, ignore);
    overrides.Add<MyClass>(m => m.DateChanged, ignore);
    Type t = typeof(List<MyClass>);
    XmlSerializer serial = new XmlSerializer(t, overrides);
like image 121
Schiavini Avatar answered Oct 01 '22 02:10

Schiavini


You may be able to exclude some properties by taking advantage of the fact that the XmlSerializer will not serialize nulls to the output. So for reference types, you can null out those properties you don't want to appear in the xml.

The resulting xml will be deserializable back into the same class, but the omitted fields will obviously be null.

However, this doesn't help for your desire to change the date format. For this, you'll need to either create a new class that has the date as a string in the format you want, or you could implement IXmlSerializable, giving you complete control over the xml. [it is worth noting that date data-type has a standard format in XML, so by changing it it won't stricly be an XML date any longer - you may not care].

[EDIT in response to your comments]

There is an additional trick you might use to "disappear" a null nullable type, but it does require a change to your class. The serializer, when serializing MyProperty - will also check if there is a property called MyProperySpecified. If it exists and returns false, the item property is not serialized:

public class Person
{
    [XmlElement]
    public string Name { get; set; }

    [XmlElement]
    public DateTime? BirthDate { get; set; }

    public bool BirthDateSpecified
    {
        get { return BirthDate.HasValue; }
    }
}

If you are prepared to add this property you can make it remove the nullable types when null. In fact - now I think about it - this may be a useful way of removing other properties too, depending on your usage scenario.

like image 22
Rob Levine Avatar answered Oct 01 '22 03:10

Rob Levine