static JObject CreateMessageRepresentation(Customer customer)
{
return new JObject(
new JProperty("customer",
new JObject(
new JProperty("name", customer.Name),
new JProperty("address",
new JObject(
new JProperty("street", customer.Address.Street),
new JProperty("zipCode", customer.Address.Zip),
new JProperty("town", customer.Address.City)
)
)
)
)
)
}
Yuck.
Just make CustomerData and AddressData classes, even if you only use them for that one API response. And even if you have ten other versions of CustomerData and AddressData for ten other methods. You get type safety and your tests refactor nicely.
@Value
static class AddressData {
String street;
String zipCode;
String town;
}
@Value
static class CustomerData {
String name;
AddressData address;
}
@Value
static class Message {
CustomerData customer;
}
public Message createMessage(Customer customer) {
final Address addy = customer.getAddress();
return new Message(new CustomerData(customer.getName(), new AddressData(addy.getStreet(), addy.getZip(), addy.getCity())));
}
You could format this nicer, and adding some constructors would help, but at least the typechecker is doing work for you.
Well you have chosen an example that is little more than an API object in the first place.
class IdealGas implements EquationOfState {
private final double gamma;
public IdealGas(double gamma) {
this.gamma = gamma;
}
public double energyDensity(double pressure, double internalEnergy) {
return (1 + gamma) * pressure * internalEnergy;
}
}
Why create a separate type over this class which is just a projection of its data? You can just use a JSONObject as the API object. You are already going to need some special tricks to deal with the union with other EquationOfStates on top of some out of band type field to designate which class is to be used.
You will have the same sort of boiler plate in either case. Either a `public EquationOfStateData getEOSData()` or a `public JSONObject getJSON()`. In one case you use type safety and the deserializer provides your validation messages but should still do some custom validation on top to handle mismatched unions, in the other case you perform the type check (ordinarily done by using method like `json.getDouble()` and get to give custom messages.
Choose your poison, they really aren't all that different.
This is a parser, not a serializer, but hopefully it's clear how this approach can be applied in the other direction. (I still have the analogous code on a branch somewhere, but the parsing logic needed a cleanup more, and sooner.)
Some of the uncurried function stuff can be cleaned up with dedicated wrappers for `BiFunction` and whatnot. And of course, the address parser could be extracted out if we want to unit test it separately.
I don't find the code I give above to be any worse than the code you gave (for that matter, I don't have the same "yuck" reaction to the C# example, either). I much prefer not needing extra data types that only serve to configure analogous translation code.
We can keep going back and forth, addressing the concerns we have about each other's approach, but it ultimately comes down to preference.
Just make CustomerData and AddressData classes, even if you only use them for that one API response. And even if you have ten other versions of CustomerData and AddressData for ten other methods. You get type safety and your tests refactor nicely.
You could format this nicer, and adding some constructors would help, but at least the typechecker is doing work for you.