Need help loading XML data into XNA 4.0 project - xml-serialization

I'd like to do this the right way if possible. I have XML data as follows:
<?xml version="1.0" encoding="utf-8"?>
<XnaContent>
<Asset Type="PG2.Dictionary">
<Letters TotalInstances="460100">
<Letter Count="34481">a</Letter>
...
<Letter Count="1361">z</Letter>
</Letters>
<Words Count="60516">
<Word>aardvark</Word>
...
<Word>zebra</Word>
</Words>
</Asset>
</XnaContent>
and I'd like to load this in (using Content.Load< Dictionary >) into one of these
namespace PG2
{
public class Dictionary
{
public class Letters
{
public int totalInstances;
public List<Character> characters;
public class Character
{
public int count;
public char character;
}
}
public class Words
{
public int count;
public HashSet<string> words;
}
Letters letters;
Words words;
}
}
Can anyone help with either instructions or pointers to tutorials? I've found a few which come close but things seem to have changed slightly between 3.1 and 4.0 in ways which I don't understand and a lot of the documentation assumes knowledge I don't have. My understanding so far is that I need to make the Dictionary class Serializable but I can't seem to make that happen. I've added the XML file to the content project but how do I get it to create the correct XNB file?
Thanks!
Charlie.

This may help Link. I found it useful to work the other way round to check that my xml data was correctly defined. Instantate your dictionary class set all the fields then serialize it to xml using a XmlSerializer to check the output.

You need to implement a ContentTypeSerializer for your Dictionary class. Put this in a content extension library and add a reference to the content extension library to your content project. Put your Dictionary class into a game library that is reference by both your game and the content extension project.
See:
http://blogs.msdn.com/b/shawnhar/archive/2008/08/26/customizing-intermediateserializer-part-2.aspx
Here is a quick ContentTypeSerializer I wrote that will deserialize your Dictionary class. It could use better error handling.
using System;
using System.Collections.Generic;
using System.Xml;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate;
namespace PG2
{
[ContentTypeSerializer]
class DictionaryXmlSerializer : ContentTypeSerializer<Dictionary>
{
private void ReadToNextElement(XmlReader reader)
{
reader.Read();
while (reader.NodeType != System.Xml.XmlNodeType.Element)
{
if (!reader.Read())
{
return;
}
}
}
private void ReadToEndElement(XmlReader reader)
{
reader.Read();
while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
{
reader.Read();
}
}
private int ReadAttributeInt(XmlReader reader, string attributeName)
{
reader.MoveToAttribute(attributeName);
return int.Parse(reader.Value);
}
protected override Dictionary Deserialize(IntermediateReader input, Microsoft.Xna.Framework.Content.ContentSerializerAttribute format, Dictionary existingInstance)
{
Dictionary dictionary = new Dictionary();
dictionary.letters = new Dictionary.Letters();
dictionary.letters.characters = new List<Dictionary.Letters.Character>();
dictionary.words = new Dictionary.Words();
dictionary.words.words = new HashSet<string>();
ReadToNextElement(input.Xml);
dictionary.letters.totalInstances = ReadAttributeInt(input.Xml, "TotalInstances");
ReadToNextElement(input.Xml);
while (input.Xml.Name == "Letter")
{
Dictionary.Letters.Character character = new Dictionary.Letters.Character();
character.count = ReadAttributeInt(input.Xml, "Count");
input.Xml.Read();
character.character = input.Xml.Value[0];
dictionary.letters.characters.Add(character);
ReadToNextElement(input.Xml);
}
dictionary.words.count = ReadAttributeInt(input.Xml, "Count");
for (int i = 0; i < dictionary.words.count; i++)
{
ReadToNextElement(input.Xml);
input.Xml.Read();
dictionary.words.words.Add(input.Xml.Value);
ReadToEndElement(input.Xml);
}
ReadToEndElement(input.Xml); // read to the end of words
ReadToEndElement(input.Xml); // read to the end of asset
return dictionary;
}
protected override void Serialize(IntermediateWriter output, Dictionary value, Microsoft.Xna.Framework.Content.ContentSerializerAttribute format)
{
throw new NotImplementedException();
}
}
}

Related

How can i store or read a animation clip data in runtime?

I'm working on a small program that can modify the animation at run time(Such as when you run faster the animation not only play faster but also with larger movement). So i need to get the existing animation, change its value, then send it back.
I found it is interesting that i can set a new curve to the animation, but i can't get access to what i already have. So I either write a file to store my animation curve (as text file for example), or i find someway to read the animation on start up.
I tried to use
AnimationUtility.GetCurveBindings(AnimationCurve);
It worked in my testing, but in some page it says this is a "Editor code", that if i build the project into a standalone program it will not work anymore. Is that true? If so, is there any way to get the curve at run time?
Thanks to the clearify from Benjamin Zach and suggestion from TehMightyPotato
I'd like to keep the idea about modifying the animation at runtime. Because it could adapt to more situations imo.
My idea for now is to write a piece of editor code that can read from the curve in Editor and output all necesseary information about the curve (keyframes) into a text file. Then read that file at runtime and create new curve to overwrite the existing one. I will leave this question open for a few days and check it to see if anyone has a better idea about it.
As said already AnimationUtility belongs to the UnityEditor namespace. This entire namespace is completely stripped of in a build and nothing in it will be available in the final app but only within the Unity Editor.
Store AnimationCurves to file
In order to store all needed information to a file you could have a script for once serializing your specific animation curve(s) in the editor before building using e.g. BinaryFormatter.Serialize. Then later on runtime you can use BinaryFormatter.Deserialize for returning the info list again.
If you wanted it more editable you could as well use e.g. JSON or XML of course
UPDATE: In general Stop using BinaryFormatter!
In the newest Unity versions the Newtonsoft Json.NET package comes already preinstalled so simply rather use JSON
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Unity.Plastic.Newtonsoft.Json;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
public class AnimationCurveManager : MonoBehaviour
{
[Serializable]
public sealed class ClipInfo
{
public int ClipInstanceID;
public List<CurveInfo> CurveInfos = new List<CurveInfo>();
// default constructor is sometimes required for (de)serialization
public ClipInfo() { }
public ClipInfo(Object clip, List<CurveInfo> curveInfos)
{
ClipInstanceID = clip.GetInstanceID();
CurveInfos = curveInfos;
}
}
[Serializable]
public sealed class CurveInfo
{
public string PathKey;
public List<KeyFrameInfo> Keys = new List<KeyFrameInfo>();
public WrapMode PreWrapMode;
public WrapMode PostWrapMode;
// default constructor is sometimes required for (de)serialization
public CurveInfo() { }
public CurveInfo(string pathKey, AnimationCurve curve)
{
PathKey = pathKey;
foreach (var keyframe in curve.keys)
{
Keys.Add(new KeyFrameInfo(keyframe));
}
PreWrapMode = curve.preWrapMode;
PostWrapMode = curve.postWrapMode;
}
}
[Serializable]
public sealed class KeyFrameInfo
{
public float Value;
public float InTangent;
public float InWeight;
public float OutTangent;
public float OutWeight;
public float Time;
public WeightedMode WeightedMode;
// default constructor is sometimes required for (de)serialization
public KeyFrameInfo() { }
public KeyFrameInfo(Keyframe keyframe)
{
Value = keyframe.value;
InTangent = keyframe.inTangent;
InWeight = keyframe.inWeight;
OutTangent = keyframe.outTangent;
OutWeight = keyframe.outWeight;
Time = keyframe.time;
WeightedMode = keyframe.weightedMode;
}
}
// I know ... singleton .. but what choices do we have? ;)
private static AnimationCurveManager _instance;
public static AnimationCurveManager Instance
{
get
{
// lazy initialization/instantiation
if (_instance) return _instance;
_instance = FindObjectOfType<AnimationCurveManager>();
if (_instance) return _instance;
_instance = new GameObject("AnimationCurveManager").AddComponent<AnimationCurveManager>();
return _instance;
}
}
// Clips to manage e.g. reference these via the Inspector
public List<AnimationClip> clips = new List<AnimationClip>();
// every animation curve belongs to a specific clip and
// a specific property of a specific component on a specific object
// for making this easier lets simply use a combined string as key
private string CurveKey(string pathToObject, Type type, string propertyName)
{
return $"{pathToObject}:{type.FullName}:{propertyName}";
}
public List<ClipInfo> ClipCurves = new List<ClipInfo>();
private string filePath = Path.Combine(Application.streamingAssetsPath, "AnimationCurves.dat");
private void Awake()
{
if (_instance && _instance != this)
{
Debug.LogWarning("Multiple Instances of AnimationCurveManager! Will ignore this one!", this);
return;
}
_instance = this;
DontDestroyOnLoad(gameObject);
// load infos on runtime
LoadClipCurves();
}
#if UNITY_EDITOR
// Call this from the ContextMenu (or later via editor script)
[ContextMenu("Save Animation Curves")]
private void SaveAnimationCurves()
{
ClipCurves.Clear();
foreach (var clip in clips)
{
var curveInfos = new List<CurveInfo>();
ClipCurves.Add(new ClipInfo(clip, curveInfos));
foreach (var binding in AnimationUtility.GetCurveBindings(clip))
{
var key = CurveKey(binding.path, binding.type, binding.propertyName);
var curve = AnimationUtility.GetEditorCurve(clip, binding);
curveInfos.Add(new CurveInfo(key, curve));
}
}
// create the StreamingAssets folder if it does not exist
try
{
if (!Directory.Exists(Application.streamingAssetsPath))
{
Directory.CreateDirectory(Application.streamingAssetsPath);
}
}
catch (IOException ex)
{
Debug.LogError(ex.Message);
}
// create a new file e.g. AnimationCurves.dat in the StreamingAssets folder
var json = JsonConvert.SerializeObject(ClipCurves);
File.WriteAllText(filePath, json);
AssetDatabase.Refresh();
}
#endif
private void LoadClipCurves()
{
if (!File.Exists(filePath))
{
Debug.LogErrorFormat(this, "File \"{0}\" not found!", filePath);
return;
}
var fileStream = new FileStream(filePath, FileMode.Open);
var json = File.ReadAllText(filePath);
ClipCurves = JsonConvert.DeserializeObject<List<ClipInfo>>(json);
}
// now for getting a specific clip's curves
public AnimationCurve GetCurve(AnimationClip clip, string pathToObject, Type type, string propertyName)
{
// either not loaded yet or error -> try again
if (ClipCurves == null || ClipCurves.Count == 0) LoadClipCurves();
// still null? -> error
if (ClipCurves == null || ClipCurves.Count == 0)
{
Debug.LogError("Apparantly no clipCurves loaded!");
return null;
}
var clipInfo = ClipCurves.FirstOrDefault(ci => ci.ClipInstanceID == clip.GetInstanceID());
// does this clip exist in the dictionary?
if (clipInfo == null)
{
Debug.LogErrorFormat(this, "The clip \"{0}\" was not found in clipCurves!", clip.name);
return null;
}
var key = CurveKey(pathToObject, type, propertyName);
var curveInfo = clipInfo.CurveInfos.FirstOrDefault(c => string.Equals(c.PathKey, key));
// does the curve key exist for the clip?
if (curveInfo == null)
{
Debug.LogErrorFormat(this, "The key \"{0}\" was not found for clip \"{1}\"", key, clip.name);
return null;
}
var keyframes = new Keyframe[curveInfo.Keys.Count];
for (var i = 0; i < curveInfo.Keys.Count; i++)
{
var keyframe = curveInfo.Keys[i];
keyframes[i] = new Keyframe(keyframe.Time, keyframe.Value, keyframe.InTangent, keyframe.OutTangent, keyframe.InWeight, keyframe.OutWeight)
{
weightedMode = keyframe.WeightedMode
};
}
var curve = new AnimationCurve(keyframes)
{
postWrapMode = curveInfo.PostWrapMode,
preWrapMode = curveInfo.PreWrapMode
};
// otherwise finally return the AnimationCurve
return curve;
}
}
Then you can do something like e.e.
AnimationCurve originalCurve = AnimationCurvesManager.Instance.GetCurve(
clip,
"some/relative/GameObject",
typeof<SomeComponnet>,
"somePropertyName"
);
the second parameter pathToObject is an empty string if the property/component is attached to the root object itself. Otherwise it is given in the hierachy path as usual for Unity like e.g. "ChildName/FurtherChildName".
Now you can change the values and assign a new curve on runtime.
Assigning new curve on runtime
On runtime you can use animator.runtimeanimatorController in order to retrieve a RuntimeAnimatorController reference.
It has a property animationClips which returns all AnimationClips assigned to this controller.
You could then use e.g. Linq FirstOrDefault in order to find a specific AnimationClip by name and finally use AnimationClip.SetCurve to assign a new animation curve to a certain component and property.
E.g. something like
// you need those of course
string clipName;
AnimationCurve originalCurve = AnimationCurvesManager.Instance.GetCurve(
clip,
"some/relative/GameObject",
typeof<SomeComponnet>,
"somePropertyName"
);
// TODO
AnimationCurve newCurve = SomeMagic(originalCurve);
// get the animator reference
var animator = animatorObject.GetComponent<Animator>();
// get the runtime Animation controller
var controller = animator.runtimeAnimatorController;
// get all clips
var clips = controller.animationClips;
// find the specific clip by name
// alternatively you could also get this as before using a field and
// reference the according script via the Inspector
var someClip = clips.FirstOrDefault(clip => string.Equals(clipName, clip.name));
// was found?
if(!someClip)
{
Debug.LogWarningFormat(this, "There is no clip called {0}!", clipName);
return;
}
// assign a new curve
someClip.SetCurve("relative/path/to/some/GameObject", typeof(SomeComponnet), "somePropertyName", newCurve);
Note: Typed on smartphone so no warranty! But I hope the idea gets clear...
Also checkout the example in AnimationClip.SetCurve → You might want to use the Animation component instead of an Animator in your specific use case.

Eclipse JDT ListRewrite inserts new node at wrong places

I'm trying to add an annotation to some selected fields using Eclipse JDT infrastructure. However, this is not run as a plugin. I added all the required dependencies to a separate project so this can be run in batch mode. However I found out that, the ListRewrite is not inserting my annotation at the right place. I have given the code below. I initially get all the field declarations in a map using a visitor and then add them one by one using the code below.
FieldDeclaration fld = lVrblDet.listStringVarMap.get(propName);
final MarkerAnnotation autoWiredAnnotate = ast.newMarkerAnnotation(); autoWiredAnnotate.setTypeName(ast.newName("MyAnnot"));
lrw = rewriter.getListRewrite(fld, FieldDeclaration.MODIFIERS2_PROPERTY);
lrw.insertLast(autoWiredAnnotate, null);
Document document = new Document(cu.toString());
try {
TextEdit edits = rewriter.rewriteAST(document, null);
edits.apply(document);
} catch (MalformedTreeException | IllegalArgumentException | BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
However the expected output is sometimes offset by 1 character.The input and output classes have been given below.
Input Class:
#SuppressWarnings("unchecked")
public class SampleClassA {
public SampleClassB classB;
public SampleClassB getClassB() {
return classB;
}
public void setClassB(SampleClassB classB) {
this.classB = classB;
}
#Deprecated
public void printNameFromSmapleClassB() {
System.out.println(this.classB.name);
}
}
Output Class:
#SuppressWarnings("unchecked") public class SampleClassA {
p #MyAnnot
ublic SampleClassB classB;
public SampleClassB getClassB(){
return classB;
}
public void setClassB( SampleClassB classB){
this.classB=classB;
}
#Deprecated public void printNameFromSmapleClassB(){
System.out.println(this.classB.name);
}
}
As you can see in the code above, the Annotation messed with the modifier. I have tried multiple combinations of insertFirst,insertLast.Examples on the net are incomplete. Can somebody point me the mistake/the right resource ?
I just couldn't get it to work with ListRewrite. I don't know what I was doing wrong. So I wrote a visitor to store all the FieldDeclarations in a map.
#Override
public boolean visit(FieldDeclaration node) {
for (Object obj : node.fragments()) {
listStringVarMap.put(((VariableDeclarationFragment) obj).getName().toString(), node);
}
return false;
}
I looped through the map and inserted the annotation nodes as a modifiers, for the declarations that met my criteria. Please do remember to turn on recormodifications for the compilation unit you are modifying.
CompilationUnit cu = jFileAst.getEquivCompilUnit();
cu.recordModifications();
FieldDeclaration fldDecl = lVrblDet.listStringVarMap.get(propName);
importVo = (JavaAnnotImportVo) javaAstNodeCreator
.createASTNode(SpringAnnotationEnum.AutowireAnnotation, ast);
cu.imports().add(importVo.getImpDecl());
fldDecl.modifiers().add(0, importVo.getAnnotNode());
Finally write to file on disk/save back. Formatting(optional) before saving is a good idea, because the node insertions mess up with the code formatting.

Way to deserialized or load last save state scene with GameObject and other classes instead of storing normal fields via binary format?

I humbly ask for help in order to solve this problem. I successfully take a quick guide to learn more about save and load state of the game. Basically first, I know how to use PlayerPrefsto store basic string, int, and float.
Now, looking for a more effective way to store saved files via serialization. At first, after my first few researches online, I watch some video tutorial and only provides storing basic fields (int, string, bool, float, etc.) and saved in a created file. I attempt to try it on classes but didn't worked unless I marked as [Serializable].
Next, trying to save Gameobject created, prefabs or not, didn't work and it requires to serialize that class itself that is "GameObject". I took first attempt using this guide from StackOverflow with the accepted answer, I do understand and saving a GameObject or other custom classes require to store it and converted into .xml file.
Here's my two main problem need to resolve. the first one is that the runtime returned NullPointerException after I ensured all of the necessary objects are created as new. The error stopped at this line (ask for more code source if you need):
DataContractSerializer ds = new DataContractSerializer (data2.GetType ()); // --> Serialize to .xml file.
MemoryStream stream = new MemoryStream();
ds.WriteObject (stream, data2); // --> The error stops here.
stream.Seek (0, SeekOrigin.Begin);
file.Write (stream.GetBuffer (), 0, stream.GetBuffer ().Length);
file.Close();
As you can see, this is the part of the code where you can save and stored in a file created on a persistent file directory for the stored classes such as GameObject, List, and/or other custom classes.
The second problem will be tackled after the first problem is resolved. The second problem involves loading last state saved. For the normal fields such as integer or string, using BinaryFormatter and FileStream works well to load stored values form a file created last time. I tried that on stored custom classes such as GameObject but it required a different method like this one but it is a bit hard to understand how to translate it in Unity and still observe some ways to work it out, the best way to load stored classes from a file.
Here is the class I'm trying to deserialize a class that contains the following fields inside.
[DataContract]
public class TreeData2 {
// - - - Spouse - - -
[DataMember] private List<GameObject> _masters;
public List<GameObject> masters {
get { return _masters; }
set { _masters = value; }
}
[DataMember] private List<GameObject> _targets;
public List<GameObject> targets {
get { return _targets; }
set { _targets = value; }
}
[DataMember] private List<FamilyDatabase> _familyGroup;
public List<FamilyDatabase> familyGroup {
get { return _familyGroup; }
set { _familyGroup = value; }
}
[DataMember] private GameObject _node;
public GameObject node {
get { return _node; }
set { _node = value; }
}
[DataMember] private List<string> _mothers;
public List<string> mothers {
get { return _mothers; }
set { _mothers = value; }
}
[DataMember] private List<string> _fathers;
public List<string> fathers {
get { return _fathers; }
set { _fathers = value; }
}
[DataMember] private List<GenerationDatabase> _genDb;
public List<GenerationDatabase> genDb {
get { return _genDb; }
set { _genDb = value; }
}
// - - - Root Action - - -
[DataMember] private List<GameObject> _child;
public List<GameObject> child {
get { return _child; }
set { _child = value; }
}
// Gen Database (Main)
[DataMember] private List<string> _mothersDB;
public List<string> mothersDB {
get { return _mothersDB; }
set { _mothersDB = value; }
}
[DataMember] private List<string> _fathersDB;
public List<string> fathersDB {
get { return _fathersDB; }
set { _fathersDB = value; }
}
[DataMember] private List<GameObject> _mastersDB;
public List<GameObject> mastersDB {
get { return _mastersDB; }
set { _mastersDB = value; }
}
[DataMember] private List<GameObject> _targetsDB;
public List<GameObject> targetsDB {
get { return _targetsDB; }
set { _targetsDB = value; }
}
[DataMember] private List<string> _mothersT;
public List<string> mothersT {
get { return _mothersT; }
set { _mothersT = value; }
}
[DataMember] private List<string> _fathersT;
public List<string> fathersT {
get { return _fathersT; }
set { _fathersT = value; }
}
[DataMember] private List<GameObject> _mastersT;
public List<GameObject> mastersT {
get { return _mastersT; }
set { _mastersT = value; }
}
[DataMember] private List<GameObject> _targetsT;
public List<GameObject> targetsT {
get { return _targetsT; }
set { _targetsT = value; }
}
}
data2 is the variable name of the TreeData2 class and yes I'm making a family tree like structure via Unity for the game that shows progress of unlocking and storing lists of the branches. Here's the recap with the mentioned variable name while serializing GameObject and List classes.
FileStream file = File.Create (Application.persistentDataPath + "/check/treeData2.dat");
TreeData2 data2 = new TreeData2();
. . .
DataContractSerializer ds = new DataContractSerializer (data2.GetType ());
MemoryStream stream = new MemoryStream();
ds.WriteObject (stream, data2); // --> Error stops here. Returns NullPointerException due to failed in parsing in .xml file in storing GameObject classes and List<T>.
stream.Seek (0, SeekOrigin.Begin);
file.Write (stream.GetBuffer (), 0, stream.GetBuffer ().Length);
file.Close();
string result = XElement.Parse(Encoding.ASCII.GetString(stream.GetBuffer()).Replace("\0", "")).ToString();
print ("SAVE TREE COMPLETE");
print ("Result: " + result);
Redirect from this original question from Game Development.
Let me start with clearing a confusion I find so often. 'Serializable' will serialize a class for display in inspector only. You can say that it will serialize your class into a format that can be represented by inspector. Often, serialize means convert into byte arrays, it doesn't have to be a byte array, it can be any other format, e.g. strings.
Unity does not allow you to save your gameobjects directly, however, it doesn't stop you from recreating them to reflect some previous state. A gameobject may have so many components, e.g. MeshRenderer, Camera, etc, and it could get rough serializing all that down, imagine some big hierarchy!.
Generally, you want to separate your behaviors from data, i.e. your MonoBehavior from model/data (not 3d model), its a common OOP practice. You can come up with how you can save and retrieve some data from disk. I used Json.Net to serialize my data models into json. That gave me flexibility to save it locally as well as send it over network, but its just an example.
For an example, if I had to serialize a user's inventory, I would make a class like this:
[Serializable]
public class Inventory
{
public List<InventoryItem> _items;
// Some serializable and transient variables
}
[Serializable]
public class InventoryItem
{
// Some serializable and transient variables
}
Then my Monobehaviour that would show inventory would look like this:
public class InventoryView : MonoBehaviour
{
public Inventory _inventory; //Now the inventory items show in the inspector also, because it is serialized.
void createViewFromInventory()
{ //... }
}
And now, anywhere I have reference to an Inventory object, I can serialize it however I wish to do so. With Json.Net, all I had to do looked something like this:
Inventory inv = getInventoryRef(); // get inventory here
string serializedInv = JsonConvert.Serialize(inv); // It converts it into json.
PlayerPrefs.Save("inventory", serializedInv); //
And in order to retrieve the saved inventory, I would do something like this:
void loadInventory()
{
string invStr = PreferPrefs.GetString("inventory");
Inventory inv = JsonConvert.Deserialize<Inventory>(invStr);
}
This way, monobehavior view classes need only ACT upon inventory state, but not save other components on the gameobject. Hope it helps.
Unfortunately, after several experiments to find the easy way to store GameObjects effectively without hassle, there is no shortcut in preserving files + game objects during save and load state. I decided to give up for banging my head too hard to go crazy in making expectations on saving scene in one go. There are many steps to understand it.
Right now, storing info on each game object's specified sections/components require complex serializable classes, a meticulous way for sharing and retrieving each part of data. Explanation on this link and for more effective way in preserving data (but still not on game object) via formatting into JSON file.
It is a wise choice to make a better roadmap for tracking last state from scratch if you want to make your own save/load state for both common variables, serializable classes, and game object.
However, there is another way to save and load GameObject using this solution found on this Unity Q&A section. It discusses about "SerializerHelper" that lets you serialize not only serialized classes but also game objects, scenes and other non-serializable classes. Check this forum as well in order to understand how it works. You can try this Unity package to try out saving/loading GO here to download. (Requires to register Dropbox account if needed.)

Get and Set attribute values of a class using aspectJ

I am using aspectj to add some field to a existing class and annotate it also.
I am using load time weaving .
Example :- I have a Class customer in which i am adding 3 string attributes. But my issues is that I have to set some values and get it also before my business call.
I am trying the below approach.
In my aj file i have added the below, my problem is in the Around pointcut , how do i get the attribute and set the attribute.
public String net.customers.PersonCustomer.getOfflineRiskCategory() {
return OfflineRiskCategory;
}
public void net.customers.PersonCustomer.setOfflineRiskCategory(String offlineRiskCategory) {
OfflineRiskCategory = offlineRiskCategory;
}
public String net.customers.PersonCustomer.getOnlineRiskCategory() {
return OnlineRiskCategory;
}
public void net.customers.PersonCustomer.setOnlineRiskCategory(String onlineRiskCategory) {
OnlineRiskCategory = onlineRiskCategory;
}
public String net.customers.PersonCustomer.getPersonCommercialStatus() {
return PersonCommercialStatus;
}
public void net.customers.PersonCustomer.setPersonCommercialStatus(String personCommercialStatus) {
PersonCommercialStatus = personCommercialStatus;
}
#Around("execution(* net.xxx.xxx.xxx.DataMigration.populateMap(..))")
public Object invoke(ProceedingJoinPoint joinPoint) throws Throwable {
Object arguments[] = joinPoint.getArgs();
if (arguments != null) {
HashMap<String, String> hMap = (HashMap) arguments[0];
PersonCustomer cus = (PersonCustomer) arguments[1];
return joinPoint.proceed();
}
If anyone has ideas please let me know.
regards,
FT
First suggestion, I would avoid mixing code-style aspectj with annotation-style. Ie- instead of #Around, use around.
Second, instead of getting the arguments from the joinPoint, you should bind them in the pointcut:
Object around(Map map, PersonCustomer cust) :
execution(* net.xxx.xxx.xxx.DataMigration.populateMap(Map, PersonCustomer) && args(map, cust) {
...
return proceed(map, cust);
}
Now, to answer your question: you also need to use intertype declarations to add new fields to your class, so do something like this:
private String net.customers.PersonCustomer.OfflineRiskCategory;
private String net.customers.PersonCustomer.OnlineRiskCategory;
private String net.customers.PersonCustomer.PersonCommercialStatus;
Note that the private keyword here means private to the aspect, not to the class that you declare it on.

Stop DataContractSerializer putting in namespace? [duplicate]

The code looks like this:
StringBuilder builder = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
using (XmlWriter xmlWriter = XmlWriter.Create(builder, settings))
{
XmlSerializer s = new XmlSerializer(objectToSerialize.GetType());
s.Serialize(xmlWriter, objectToSerialize);
}
The resulting serialized document includes namespaces, like so:
<message xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"
xmlns="urn:something">
...
</message>
To remove the xsi and xsd namespaces, I can follow the answer from How to serialize an object to XML without getting xmlns=”…”?.
I want my message tag as <message> (without any namespace attributes). How can I do this?
...
XmlSerializer s = new XmlSerializer(objectToSerialize.GetType());
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("","");
s.Serialize(xmlWriter, objectToSerialize, ns);
This is the 2nd of two answers.
If you want to just strip all namespaces arbitrarily from a document during serialization, you can do this by implementing your own XmlWriter.
The easiest way is to derive from XmlTextWriter and override the StartElement method that emits namespaces. The StartElement method is invoked by the XmlSerializer when emitting any elements, including the root. By overriding the namespace for each element, and replacing it with the empty string, you've stripped the namespaces from the output.
public class NoNamespaceXmlWriter : XmlTextWriter
{
//Provide as many contructors as you need
public NoNamespaceXmlWriter(System.IO.TextWriter output)
: base(output) { Formatting= System.Xml.Formatting.Indented;}
public override void WriteStartDocument () { }
public override void WriteStartElement(string prefix, string localName, string ns)
{
base.WriteStartElement("", localName, "");
}
}
Suppose this is the type:
// explicitly specify a namespace for this type,
// to be used during XML serialization.
[XmlRoot(Namespace="urn:Abracadabra")]
public class MyTypeWithNamespaces
{
// private fields backing the properties
private int _Epoch;
private string _Label;
// explicitly define a distinct namespace for this element
[XmlElement(Namespace="urn:Whoohoo")]
public string Label
{
set { _Label= value; }
get { return _Label; }
}
// this property will be implicitly serialized to XML using the
// member name for the element name, and inheriting the namespace from
// the type.
public int Epoch
{
set { _Epoch= value; }
get { return _Epoch; }
}
}
Here's how you would use such a thing during serialization:
var o2= new MyTypeWithNamespaces { ..intializers.. };
var builder = new System.Text.StringBuilder();
using ( XmlWriter writer = new NoNamespaceXmlWriter(new System.IO.StringWriter(builder)))
{
s2.Serialize(writer, o2, ns2);
}
Console.WriteLine("{0}",builder.ToString());
The XmlTextWriter is sort of broken, though. According to the reference doc, when it writes it does not check for the following:
Invalid characters in attribute and element names.
Unicode characters that do not fit the specified encoding. If the Unicode
characters do not fit the specified
encoding, the XmlTextWriter does not
escape the Unicode characters into
character entities.
Duplicate attributes.
Characters in the DOCTYPE public
identifier or system identifier.
These problems with XmlTextWriter have been around since v1.1 of the .NET Framework, and they will remain, for backward compatibility. If you have no concerns about those problems, then by all means use the XmlTextWriter. But most people would like a bit more reliability.
To get that, while still suppressing namespaces during serialization, instead of deriving from XmlTextWriter, define a concrete implementation of the abstract XmlWriter and its 24 methods.
An example is here:
public class XmlWriterWrapper : XmlWriter
{
protected XmlWriter writer;
public XmlWriterWrapper(XmlWriter baseWriter)
{
this.Writer = baseWriter;
}
public override void Close()
{
this.writer.Close();
}
protected override void Dispose(bool disposing)
{
((IDisposable) this.writer).Dispose();
}
public override void Flush()
{
this.writer.Flush();
}
public override string LookupPrefix(string ns)
{
return this.writer.LookupPrefix(ns);
}
public override void WriteBase64(byte[] buffer, int index, int count)
{
this.writer.WriteBase64(buffer, index, count);
}
public override void WriteCData(string text)
{
this.writer.WriteCData(text);
}
public override void WriteCharEntity(char ch)
{
this.writer.WriteCharEntity(ch);
}
public override void WriteChars(char[] buffer, int index, int count)
{
this.writer.WriteChars(buffer, index, count);
}
public override void WriteComment(string text)
{
this.writer.WriteComment(text);
}
public override void WriteDocType(string name, string pubid, string sysid, string subset)
{
this.writer.WriteDocType(name, pubid, sysid, subset);
}
public override void WriteEndAttribute()
{
this.writer.WriteEndAttribute();
}
public override void WriteEndDocument()
{
this.writer.WriteEndDocument();
}
public override void WriteEndElement()
{
this.writer.WriteEndElement();
}
public override void WriteEntityRef(string name)
{
this.writer.WriteEntityRef(name);
}
public override void WriteFullEndElement()
{
this.writer.WriteFullEndElement();
}
public override void WriteProcessingInstruction(string name, string text)
{
this.writer.WriteProcessingInstruction(name, text);
}
public override void WriteRaw(string data)
{
this.writer.WriteRaw(data);
}
public override void WriteRaw(char[] buffer, int index, int count)
{
this.writer.WriteRaw(buffer, index, count);
}
public override void WriteStartAttribute(string prefix, string localName, string ns)
{
this.writer.WriteStartAttribute(prefix, localName, ns);
}
public override void WriteStartDocument()
{
this.writer.WriteStartDocument();
}
public override void WriteStartDocument(bool standalone)
{
this.writer.WriteStartDocument(standalone);
}
public override void WriteStartElement(string prefix, string localName, string ns)
{
this.writer.WriteStartElement(prefix, localName, ns);
}
public override void WriteString(string text)
{
this.writer.WriteString(text);
}
public override void WriteSurrogateCharEntity(char lowChar, char highChar)
{
this.writer.WriteSurrogateCharEntity(lowChar, highChar);
}
public override void WriteValue(bool value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(DateTime value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(decimal value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(double value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(int value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(long value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(object value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(float value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(string value)
{
this.writer.WriteValue(value);
}
public override void WriteWhitespace(string ws)
{
this.writer.WriteWhitespace(ws);
}
public override XmlWriterSettings Settings
{
get
{
return this.writer.Settings;
}
}
protected XmlWriter Writer
{
get
{
return this.writer;
}
set
{
this.writer = value;
}
}
public override System.Xml.WriteState WriteState
{
get
{
return this.writer.WriteState;
}
}
public override string XmlLang
{
get
{
return this.writer.XmlLang;
}
}
public override System.Xml.XmlSpace XmlSpace
{
get
{
return this.writer.XmlSpace;
}
}
}
Then, provide a derived class that overrides the StartElement method, as before:
public class NamespaceSupressingXmlWriter : XmlWriterWrapper
{
//Provide as many contructors as you need
public NamespaceSupressingXmlWriter(System.IO.TextWriter output)
: base(XmlWriter.Create(output)) { }
public NamespaceSupressingXmlWriter(XmlWriter output)
: base(XmlWriter.Create(output)) { }
public override void WriteStartElement(string prefix, string localName, string ns)
{
base.WriteStartElement("", localName, "");
}
}
And then use this writer like so:
var o2= new MyTypeWithNamespaces { ..intializers.. };
var builder = new System.Text.StringBuilder();
var settings = new XmlWriterSettings { OmitXmlDeclaration = true, Indent= true };
using ( XmlWriter innerWriter = XmlWriter.Create(builder, settings))
using ( XmlWriter writer = new NamespaceSupressingXmlWriter(innerWriter))
{
s2.Serialize(writer, o2, ns2);
}
Console.WriteLine("{0}",builder.ToString());
Credit for this to Oleg Tkachenko.
After reading Microsoft's documentation and several solutions online, I have discovered the solution to this problem. It works with both the built-in XmlSerializer and custom XML serialization via IXmlSerialiazble.
To wit, I'll use the same MyTypeWithNamespaces XML sample that's been used in the answers to this question so far.
[XmlRoot("MyTypeWithNamespaces", Namespace="urn:Abracadabra", IsNullable=false)]
public class MyTypeWithNamespaces
{
// As noted below, per Microsoft's documentation, if the class exposes a public
// member of type XmlSerializerNamespaces decorated with the
// XmlNamespacesDeclarationAttribute, then the XmlSerializer will utilize those
// namespaces during serialization.
public MyTypeWithNamespaces( )
{
this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
// Don't do this!! Microsoft's documentation explicitly says it's not supported.
// It doesn't throw any exceptions, but in my testing, it didn't always work.
// new XmlQualifiedName(string.Empty, string.Empty), // And don't do this:
// new XmlQualifiedName("", "")
// DO THIS:
new XmlQualifiedName(string.Empty, "urn:Abracadabra") // Default Namespace
// Add any other namespaces, with prefixes, here.
});
}
// If you have other constructors, make sure to call the default constructor.
public MyTypeWithNamespaces(string label, int epoch) : this( )
{
this._label = label;
this._epoch = epoch;
}
// An element with a declared namespace different than the namespace
// of the enclosing type.
[XmlElement(Namespace="urn:Whoohoo")]
public string Label
{
get { return this._label; }
set { this._label = value; }
}
private string _label;
// An element whose tag will be the same name as the property name.
// Also, this element will inherit the namespace of the enclosing type.
public int Epoch
{
get { return this._epoch; }
set { this._epoch = value; }
}
private int _epoch;
// Per Microsoft's documentation, you can add some public member that
// returns a XmlSerializerNamespaces object. They use a public field,
// but that's sloppy. So I'll use a private backed-field with a public
// getter property. Also, per the documentation, for this to work with
// the XmlSerializer, decorate it with the XmlNamespaceDeclarations
// attribute.
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces
{
get { return this._namespaces; }
}
private XmlSerializerNamespaces _namespaces;
}
That's all to this class. Now, some objected to having an XmlSerializerNamespaces object somewhere within their classes; but as you can see, I neatly tucked it away in the default constructor and exposed a public property to return the namespaces.
Now, when it comes time to serialize the class, you would use the following code:
MyTypeWithNamespaces myType = new MyTypeWithNamespaces("myLabel", 42);
/******
OK, I just figured I could do this to make the code shorter, so I commented out the
below and replaced it with what follows:
// You have to use this constructor in order for the root element to have the right namespaces.
// If you need to do custom serialization of inner objects, you can use a shortened constructor.
XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces), new XmlAttributeOverrides(),
new Type[]{}, new XmlRootAttribute("MyTypeWithNamespaces"), "urn:Abracadabra");
******/
XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces),
new XmlRootAttribute("MyTypeWithNamespaces") { Namespace="urn:Abracadabra" });
// I'll use a MemoryStream as my backing store.
MemoryStream ms = new MemoryStream();
// This is extra! If you want to change the settings for the XmlSerializer, you have to create
// a separate XmlWriterSettings object and use the XmlTextWriter.Create(...) factory method.
// So, in this case, I want to omit the XML declaration.
XmlWriterSettings xws = new XmlWriterSettings();
xws.OmitXmlDeclaration = true;
xws.Encoding = Encoding.UTF8; // This is probably the default
// You could use the XmlWriterSetting to set indenting and new line options, but the
// XmlTextWriter class has a much easier method to accomplish that.
// The factory method returns a XmlWriter, not a XmlTextWriter, so cast it.
XmlTextWriter xtw = (XmlTextWriter)XmlTextWriter.Create(ms, xws);
// Then we can set our indenting options (this is, of course, optional).
xtw.Formatting = Formatting.Indented;
// Now serialize our object.
xs.Serialize(xtw, myType, myType.Namespaces);
Once you have done this, you should get the following output:
<MyTypeWithNamespaces>
<Label xmlns="urn:Whoohoo">myLabel</Label>
<Epoch>42</Epoch>
</MyTypeWithNamespaces>
I have successfully used this method in a recent project with a deep hierachy of classes that are serialized to XML for web service calls. Microsoft's documentation is not very clear about what to do with the publicly accesible XmlSerializerNamespaces member once you've created it, and so many think it's useless. But by following their documentation and using it in the manner shown above, you can customize how the XmlSerializer generates XML for your classes without resorting to unsupported behavior or "rolling your own" serialization by implementing IXmlSerializable.
It is my hope that this answer will put to rest, once and for all, how to get rid of the standard xsi and xsd namespaces generated by the XmlSerializer.
UPDATE: I just want to make sure I answered the OP's question about removing all namespaces. My code above will work for this; let me show you how. Now, in the example above, you really can't get rid of all namespaces (because there are two namespaces in use). Somewhere in your XML document, you're going to need to have something like xmlns="urn:Abracadabra" xmlns:w="urn:Whoohoo. If the class in the example is part of a larger document, then somewhere above a namespace must be declared for either one of (or both) Abracadbra and Whoohoo. If not, then the element in one or both of the namespaces must be decorated with a prefix of some sort (you can't have two default namespaces, right?). So, for this example, Abracadabra is the defalt namespace. I could inside my MyTypeWithNamespaces class add a namespace prefix for the Whoohoo namespace like so:
public MyTypeWithNamespaces
{
this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
new XmlQualifiedName(string.Empty, "urn:Abracadabra"), // Default Namespace
new XmlQualifiedName("w", "urn:Whoohoo")
});
}
Now, in my class definition, I indicated that the <Label/> element is in the namespace "urn:Whoohoo", so I don't need to do anything further. When I now serialize the class using my above serialization code unchanged, this is the output:
<MyTypeWithNamespaces xmlns:w="urn:Whoohoo">
<w:Label>myLabel</w:Label>
<Epoch>42</Epoch>
</MyTypeWithNamespaces>
Because <Label> is in a different namespace from the rest of the document, it must, in someway, be "decorated" with a namespace. Notice that there are still no xsi and xsd namespaces.
XmlSerializer sr = new XmlSerializer(objectToSerialize.GetType());
TextWriter xmlWriter = new StreamWriter(filename);
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add(string.Empty, string.Empty);
sr.Serialize(xmlWriter, objectToSerialize, namespaces);
This is the first of my two answers to the question.
If you want fine control over the namespaces - for example if you want to omit some of them but not others, or if you want to replace one namespace with another, you can do this using XmlAttributeOverrides.
Suppose you have this type definition:
// explicitly specify a namespace for this type,
// to be used during XML serialization.
[XmlRoot(Namespace="urn:Abracadabra")]
public class MyTypeWithNamespaces
{
// private fields backing the properties
private int _Epoch;
private string _Label;
// explicitly define a distinct namespace for this element
[XmlElement(Namespace="urn:Whoohoo")]
public string Label
{
set { _Label= value; }
get { return _Label; }
}
// this property will be implicitly serialized to XML using the
// member name for the element name, and inheriting the namespace from
// the type.
public int Epoch
{
set { _Epoch= value; }
get { return _Epoch; }
}
}
And this serialization pseudo-code:
var o2= new MyTypeWithNamespaces() { ..initializers...};
ns.Add( "", "urn:Abracadabra" );
XmlSerializer s2 = new XmlSerializer(typeof(MyTypeWithNamespaces));
s2.Serialize(System.Console.Out, o2, ns);
You would get something like this XML:
<MyTypeWithNamespaces xmlns="urn:Abracadabra">
<Label xmlns="urn:Whoohoo">Cimsswybclaeqjh</Label>
<Epoch>97</Epoch>
</MyTypeWithNamespaces>
Notice that there is a default namespace on the root element, and there is also a distinct namespace on the "Label" element. These namespaces were dictated by the attributes decorating the type, in the code above.
The Xml Serialization framework in .NET includes the possibility to explicitly override the attributes that decorate the actual code. You do this with the XmlAttributesOverrides class and friends. Suppose I have the same type, and I serialize it this way:
// instantiate the container for all attribute overrides
XmlAttributeOverrides xOver = new XmlAttributeOverrides();
// define a set of XML attributes to apply to the root element
XmlAttributes xAttrs1 = new XmlAttributes();
// define an XmlRoot element (as if [XmlRoot] had decorated the type)
// The namespace in the attribute override is the empty string.
XmlRootAttribute xRoot = new XmlRootAttribute() { Namespace = ""};
// add that XmlRoot element to the container of attributes
xAttrs1.XmlRoot= xRoot;
// add that bunch of attributes to the container holding all overrides
xOver.Add(typeof(MyTypeWithNamespaces), xAttrs1);
// create another set of XML Attributes
XmlAttributes xAttrs2 = new XmlAttributes();
// define an XmlElement attribute, for a type of "String", with no namespace
var xElt = new XmlElementAttribute(typeof(String)) { Namespace = ""};
// add that XmlElement attribute to the 2nd bunch of attributes
xAttrs2.XmlElements.Add(xElt);
// add that bunch of attributes to the container for the type, and
// specifically apply that bunch to the "Label" property on the type.
xOver.Add(typeof(MyTypeWithNamespaces), "Label", xAttrs2);
// instantiate a serializer with the overrides
XmlSerializer s3 = new XmlSerializer(typeof(MyTypeWithNamespaces), xOver);
// serialize
s3.Serialize(System.Console.Out, o2, ns2);
The result looks like this;
<MyTypeWithNamespaces>
<Label>Cimsswybclaeqjh</Label>
<Epoch>97</Epoch>
</MyTypeWithNamespaces>
You have stripped the namespaces.
A logical question is, can you strip all namespaces from arbitrary types during serialization, without going through the explicit overrides? The answer is YES, and how to do it is in my next response.