ooof after dawdling on it for like two months i finally got the hell's half-acre plant parser to a stable state. not a working stable state, mind you. just one that doesn't crash.
(okay admittedly about half the delay here was because i got super sick. but. half the delay was just me being lazy.)
it was also an interesting test of coming back to java after some time away? the language itself still seems fairly painless, it's just that everything built on top of it seems... bad. or maybe "unwieldy"; i'm in this situation where i'm using GSON (the google json library) to decode data files. the default is apparently to use reflection to shotgun all object properties into a json object, and then do the reverse when deserializing. (i didn't actually try running it with any defaults, because it seemed like that would be a huge mess.) but you can also write a custom serializer/deserializer, which lets you shape the files a little bit smoother. so far so good.
there are a few things that go wrong at this point.
first, the deserializers take the form of a type instance:
secondly, you have to explicitly register these custom deserializers, on a per-value basic -- the deserialization is all done through a class
(an aside:
where registering gets really annoying, though, is when you have nested objects to deserialize. because those deserializing instances then need to call
so that
and it's kind of a gigantic mess of boilerplate.
third, it seems like manually writing deserializers isn't really encouraged -- it sounds like the suggested workflow is dumping and restoring huge opaque data globs that contain all the perhaps-transitory internal state, and trusting that nothing in the internals of the type has changed between when it got dumped and when it got restored. so what you actually have to write for the
ISN'T EXACTLY AN IMPROVEMENT HERE. might as well just wrap a
anyway it's working but not as flexible as it needs to be, and it's not loading/using the textures correctly or something. still, it's nice making progress on this again.
(okay admittedly about half the delay here was because i got super sick. but. half the delay was just me being lazy.)
it was also an interesting test of coming back to java after some time away? the language itself still seems fairly painless, it's just that everything built on top of it seems... bad. or maybe "unwieldy"; i'm in this situation where i'm using GSON (the google json library) to decode data files. the default is apparently to use reflection to shotgun all object properties into a json object, and then do the reverse when deserializing. (i didn't actually try running it with any defaults, because it seemed like that would be a huge mess.) but you can also write a custom serializer/deserializer, which lets you shape the files a little bit smoother. so far so good.
there are a few things that go wrong at this point.
first, the deserializers take the form of a type instance:
class ... implements JsonDeserializer<T>
. this means, barring any wacky class Thing<T> implements JsonDeserializer<T>
antics (where you'd have to instance them with a deserialize function, i guess?), you're stuck making one class per type you want to deserialize. and because of the way java works, each class needs to be in its own code file. if you have ten data structures to decode, you're gonna need an entire folder devoted to those ten classes that exist only to be instanced once.secondly, you have to explicitly register these custom deserializers, on a per-value basic -- the deserialization is all done through a class
Gson
, which instances of have a fromJson
function. if you want it to check for custom deserializers, you need to build a gson value, and call .registerTypeAdapter(Type type, Object typeAdapter)
on it. the object is an instance of a thing with the correct deserializing instance, and the type is the type it deserializes. it's entirely possible for them to not match, and i have no clue what happens if they do.(an aside:
Type
here is generally the .class
value of the type, but since parametric types (Type<T>
) don't have .class values, you have to make a type token for them. this isn't really that annoying, but it's another example of how the basic unit of code in java is assumed to be the class, not the instance.)where registering gets really annoying, though, is when you have nested objects to deserialize. because those deserializing instances then need to call
fromJson
from within their deserialize
functions. which appears to mean that i need to have code likeThingDeserializer thingDeserializer = new ThingDeserializer();
Gson gson = new gsonBuilder()
.registerTypeAdapter (Thing.class, thingDeserializer)
.create();
thingDeserializer.setGson (gson);
so that
thingDeserializer
has a gson value with all the custom handlers set that it can use in its deserializing function. only since there are like ten of them, it's actually more likeFooDeserializer fooDeserializer = new FooDeserializer();
BarDeserializer barDeserializer = new BarDeserializer();
BazDeserializer bazDeserializer = new BazDeserializer();
QuuxDeserializer quuxDeserializer = new QuuxDeserializer();
BlorchDeserializer blorchDeserializer = new BlorchDeserializer();
Gson gson = new gsonBuilder()
.registerTypeAdapter (Foo.class, fooDeserializer)
.registerTypeAdapter (Bar.class, barDeserializer)
.registerTypeAdapter (Baz.class, bazDeserializer)
.registerTypeAdapter (Quux.class, quuxDeserializer)
.registerTypeAdapter (Blorch.class, blorchDeserializer)
.create();
fooDeserializer.setGson (gson);
barDeserializer.setGson (gson);
bazDeserializer.setGson (gson);
quuxDeserializer.setGson (gson);
blorchDeserializer.setGson (gson);
and it's kind of a gigantic mess of boilerplate.
third, it seems like manually writing deserializers isn't really encouraged -- it sounds like the suggested workflow is dumping and restoring huge opaque data globs that contain all the perhaps-transitory internal state, and trusting that nothing in the internals of the type has changed between when it got dumped and when it got restored. so what you actually have to write for the
deserialize
function is like. hey here's a JsonElement
that you can call .getAsInt
or .getAsJsonArray
or .getAsJsonObject
or .getAsString
on, and i guess from all of those things you need to cobble together some parsing. like, if you have "{"name": "foobar"}"
, to get to the name value you'd have to have, like, elem.getAsJsonObject.get("name").getAsString()
, and if any of those lookups don't correspond to the data, well, i hope you enjoy null reference errors. (i've been wrapping them in Optional, but that can only really do so much, and like,Optional.of(elem)
.map (e -> e.getAsJsonObject())
.map (e -> e.get("name"))
.map (e -> e.getAsString())
ISN'T EXACTLY AN IMPROVEMENT HERE. might as well just wrap a
try
around everything and hope for the best.)anyway it's working but not as flexible as it needs to be, and it's not loading/using the textures correctly or something. still, it's nice making progress on this again.