java polymorphic - ecologylab/simpl GitHub Wiki
Introduction
Java Annotated Classes
Creating Translation Scope
Serialization & De-serialization
Game Data XML
End notes
Here we give an example of using poly-morphic collections with s.im.pl serialization. In this example we will use GameData as our case study. There are situations when building multi-player games the client and the server needs to communicated with each other by transferring game data from client to server and vice versa. We will show here how to annotate java class which has poly-morphic collections.
To view this tutorial you will need to download the entire simplTutorials, simplTranslators and ecologylabFundamental projects. Access to the ecologylab fundamental project source is available through anonymous SVN access (user: anonymous, password: anonymous).
The source for this tutorial is located under /trunk/simplTutorials/trunk/src/tutorials/
Below is a set of annotated Java classes similar to the one presented in the Java "getting started" tutorial. The major difference is that we are now working with polymorphic collections.
Below is a code excerpt from game data which defines fields we want to translate as attributes of game data in an XML file.
public class GameData<G extends Goal, T extends Threat> extends
ElementState
{
@simpl_scalar
protected long timestamp;
/** Number of game cycles remaining. */
@simpl_scalar
protected int cycRem;
/**
* Indicates that, if the game is running, it should be paused; by default, the game starts this
* way and a user needs to activate it.
*/
@simpl_scalar
protected boolean paused = false;
@simpl_scalar
protected boolean loaded = false;
Below we annotate further GameData with some more attributes and a polymorphic collections of "threats". This array list can hold threat objects and subclasses of threats.
/**
* Game state flag indicating that the game is currently executing play cycles.
*/
@simpl_scalar
protected boolean running = false;
/** Game state flag indicating that the players have won the game. */
@simpl_scalar
protected boolean won = false;
/** List of Threat objects. */
@simpl_classes(
{ Threat.class, SingleSeekerThreat.class, OrbitingThreat.class, RepellableThreat.class,
PatrollingThreat.class })
@simpl_collection
protected ArrayList<T> threats = new ArrayList<T>();
@simpl_scalar
protected double score = 0;
/** No-argument constructor, required for ElementState. */
public GameData()
{
super();
}
}
Here we also annotate a threat class which itself does not hold any attributes. However, some attributes are derived from the "Targetter" class. We do not present the "Targetter" class here for simplicity.
@simpl_inherit
@xml_tag("t")
public class Threat extends Targetter
{
/**
* No-argument constructor, required for ElementState.
*/
public Threat()
{
super();
}
}
Here we derive the "Threat" class to "OrbitingThreat" class. It does not define any new new attributes but it defines a new tag "ot" as a class attribute.
@simpl_inherit
@xml_tag("ot")
public class OrbitingThreat extends Threat
{
/** Constructor stub for XML translation. */
public OrbitingThreat()
{
}
}
Here we show how to create a translation scope by providing the translation scope class with the set of classes the xml file will bind to.
/*
* Creating Translation Scope of all the classes used by game data object
*/
private static TranslationScope get()
{
TranslationScope tScope = TranslationScope.get("gamedata", GameData.class,
Threat.class, SingleSeekerThreat.class, OrbitingThreat.class, RepellableThreat.class,
PatrollingThreat.class, SeekerAvatar.class, LocationAwareSeekerAvatar.class,
Targetter.class, Mover.class, Entity.class, ColState.class);
return tScope;
}
In the code below we de-serialize a sample XML file containing game data. We call the static function on ElementState class, "translateFromXML" and provide the file path of the sample file.
We again serialize the GameData object and verify the produced XML file is the same as we supplied as input.
try
{
/*
* Get translation scope
*/
TranslationScope tScope = get();
String fileData = readFileAsStringFile("src/tutorials/polymorphic/GameData.xml");
/*
* Translating back from sample gameData file
*/
GameData<?> gd = (GameData<?>) tScope.deserializeCharSequence(fileData);
/*
* Translating the game data back to XML
*/
gd.serialize(new File("ecologylab/tutorials/polymorphic/output.xml"));
//Again to console
gd.serialize(System.out);
}
catch (Exception e)
{
e.printStackTrace();
}
Below is the sample XML file we have used as our GameData. We can see that there are three different types of threats. Which are subclasses of "Threat" and belongs to the same collection
<game_data timestamp="1234399958508" cyc_rem="8078" loaded="true"
running="true" score="-28.066665835678577">
<threats>
<nt t_val="-1.0" id="_t12" ord="12">
<dir x="-1" y="-0.09" />
<vel x="-2.88" y="-0.26" />
<pos x="171.46" y="904.72" />
</nt>
<ot t_val="-1.0" id="_t13" ord="13">
<dir x="0.4" y="-0.92" />
<vel x="0.24" y="-0.38" />
<pos x="925.46" y="114.26" />
</ot>
<ot t_val="-1.0" id="_t14" ord="14">
<dir x="0.82" y="-0.58" />
<vel x="0.78" y="-0.58" />
<pos x="88.1" y="542.74" />
</ot>
<ot t_val="-1.0" id="_t15" ord="15">
<dir x="0.94" y="-0.35" />
<vel x="1.87" y="-0.62" />
<pos x="530.98" y="549.86" />
</ot>
<pt t_val="-1.0" id="_t16" ord="16">
<dir x="0.98" y="0.21" />
<vel x="2.02" y="0.46" />
<pos x="580.81" y="702.55" />
</pt>
<pt t_val="-1.0" id="_t17" ord="17">
<dir x="-0.99" y="-0.1" />
<vel x="-2.37" y="-0.24" />
<pos x="122.95" y="900.95" />
</pt>
<pt t_val="-5.300337003285493" id="_t18" ord="18">
<dir x="-0.81" y="-0.59" />
<vel x="-1.22" y="-0.77" />
<pos x="334.58" y="734.4" />
</pt>
<pt t_val="-1.0" id="_t19" ord="19">
<dir x="-1" y="-0.04" />
<vel x="-2.43" y="-0.14" />
<pos x="863.92" y="750.44" />
</pt>
</threats>
</game_data>
So that's it! We have successfully serialized and deserialized polymorphic collections in java.