As of now I have an object that looks similar to the below.
public class DataField implements JSONable
{
public final String name;
public final Class<?> typeClass;
private Object data;
public <T> DataField(String name, Class<T> typeClass)
{
this.name = name;
this.typeClass = typeClass;
data = null;
}
public <T> T getData(Class<T> passClass)
{
if(!typeClass.equals(passClass))
throw new TypeMismatchException("Type mismatch");
return passClass.cast(data);
}
public <T> T setData(T obj, Class<T> passClass)
{
if(!typeClass.equals(passClass))
throw new TypeMismatchException("Type mismatch");
data = (Object) obj;
}
public String toJSON()
{
//The part that bugs me
StringBuilder sb = new StringBuilder();
switch(type)
{
case "myPackage.DataField":
if(isArray)
return TakesADataObjOrCollectionOfDataObjs(sb,Arrays.asList(get(DataObj[].class)));
else
return TakesADataObjOrCollectionOfDataObjs(sb,get(DataObj.class));
break;
default:
if(isArray)
TakesAnObjectOrCollection(sb,Arrays.asList(get(Object[].class)));
else
TakesAnObjectOrCollection(sb,get(Object.class));
break;
}
return sb.toString();
}
}
//I did not include code for DataObj but it has a HashMap<String,DataField>
//fields on it and two functions for getting and setting field data
//without actually divulging the field objects themselves.
Background: The problem is with this last toJSON
function. I have two different functions (listed here as TakesADataObjOrCollectionOfDataObjs
and TakesAnObjectOrCollection
) which do different things based on if the object implements JSONable
or not. Now I cannot simplify these all down to one function and let the compiler choose because with type erasure, I cannot have a function that takes both Collection<?>
and Collection<? extends JSONable>
as they have the same function signature.
It was easy when I only had to differentiate between just Object
and DataObj
types (it's a pretty simple check and all I have to do is pass in the Class<?>
of the type we're working with) but now I need to start storing List<?>
and List<? extends JSONable>
.
Current Solution: I do have a bit of code for this solution but it is not the same as what's pictured above. The current solution is to just include the type of the generic that I'm using as well like having typeClass
and a genericTypeClass
. The problem with this is it starts becoming really messy because:
typeClass
would need two methods now, one that takes both typeClass
and genericTypeClass
and one that takes typeClass
but sets genericTypeClass
to null.toJSON
switch statement would be filled with more cases, one for each supported generic, and then under each of those, checking the genericTypeClass
to see if it's a DataObj
or not.
Question: Is there any other way that I could create this class to do what I want (store differing data yet still be able to output different JSON based on the type the DataField
holds)?
Hopefully just explaining the situation and not asking 3 or 4 other related questions will stop me from falling prey to the XY Problem by just asking this.
I would recommend you to use Jackson to convert your objects into JSON Strings.
It is really easy to get to work (seriously) and it could save you a lot of time and potential errors... It also supports some features that you could use, I'm thinking about the serialization of List
s for example :)
Here is a link to an interesting blog to get you going with Jackson Json.
And here is a link to the download page for Jackson Json.
Below is a little example I just made to show you how to work with it:
public class Main {
public final String mainStr = "Hello";
public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
final ObjectMapper om = new ObjectMapper();
System.out.println("Serialized Main: " + om.writeValueAsString(new Main()));
System.out.println("Serialized A: " + om.writeValueAsString(new A()));
System.out.println("Serialized AA: " + om.writeValueAsString(new AA()));
System.out.println("Serialized B: " + om.writeValueAsString(new B()));
System.out.println("Serialized List of A: " + om.writeValueAsString(Collections.singletonList(new A())));
}
static class A extends Main {
public final String aStr = "World";
public final int aInt = 42;
}
static class AA extends A {
public final String aaStr = "Foo";
}
static class B {
public final String bStr = "Bar";
public final boolean bBool = true;
}
}
Ouptut:
Serialized Main: {"mainStr":"Hello"}
Serialized A: {"mainStr":"Hello","aStr":"World","aInt":42}
Serialized AA: {"mainStr":"Hello","aStr":"World","aInt":42,"aaStr":"Foo"}
Serialized B: {"bStr":"Bar","bBool":true}
Serialized List of A: [{"mainStr":"Hello","aStr":"World","aInt":42}]
If you have troubles making it work, we could discuss it on the chat and I could give you more help there.
Cheers!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With