How do I correctly use generics? - java

I basically am making webrequests and recieving a JSON response. Depending on the request, I am parsing JSON request into objects I have created. The parsing is pretty much the same no matter what the object Im parsing into looks like. So I have a bunch of methods doing the same work only with different objects, I was wondering how I could accomplish this with generics? Here is an example
public static ArrayList<Contact> parseStuff(String responseData) {
ArrayList<Person> People = new ArrayList<Person>();
try {
JSONArray jsonPeople = new JSONArray(responseData);
if (!jsonPeople.isNull(0)) {
for (int i = 0; i < jsonPeople.length(); i++) {
People.add(new Person(jsonPeople.getJSONObject(i)));
}
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
}
return People;
}

You should look at Effective Java 2, Item 29: Consider typesafe heterogeneous type containers
The basic idea is that you could imagine you have some Deserializer interface. Then you can have a Map<Class<?>, Deserializer<String, Object>>. The map is basically a registry from type to the proper Deserializer for that type (which deserializes from a String (perhaps you want a json type or something instead of String, but String works) to the type of interest.
The real trick is that you must enforce that the class key type matches the deserializer type. i.e. - For some Class that is a key in the map, you have a Deserializer as a value. You can do this with a generic method. For example:
<T> void put(Class<T> clazz, Deserializer<String, T> deserializer) {
map.put(clazz, deserializer);
}
Then to use the heterogeneous map, you can use a generic method again:
<T> T deserialize(Class<T> typeToDeserializeFromJson, String toDeserialize) {
return typeToDeserializeFromJson.cast(
deserializers.get(tTDFJ).deserialize(toDeserialize));
}
You use the type that is specified by the method caller to
lookup the right `Deserializer`
deserialize the json text to an `Object`
safely cast the `Object` to the right type which we know is safe because of how we constructed the map in the first place.
I hope what I said was at least somewhat clear. Reading the corresponding entry in EJ2 should help!
UPDATE:
As Abhinav points out, the GSON library will help you accomplish your final goal of deserializing objects in a way that uses generics appropriately. However, I think your question is more about generics than the end goal so I feel my answer is more appropriate. GSON must be implemented using a heterogeneous type container :-).
Thanks, Abhinav for pointing out GSON!

I would suggest you use GSON instead of JSON. It really simplifies your life.

Related

Deserialize custom types without concrete JavaType definition with Jackson

I am asking myself if (and how) it would be possible to convert specific pre-defined types with Jackson.
Given an example structure like:
{
"dataValues": {"x": <anything>[, ...]}
}
Basically it's a map that can have anything as
simple type values (like String, int...)
another map like anything
list of anything
a custom type (! here comes the problem)
As you can already see, there are a few options and at runtime unknown cascades/wraps.
The only thing I know for sure is Map<String, Object> dataValues.
Inspired by the idea around the type info (first solution approach), my rough idea is to have the custom type defined as:
{"type": "MyCustomType", "a":"Value1", "b":"Value2"}
I already tried to work my way into this using #JsonTypeInfo (and subtypes, also activateDefaultTypeMapping...) but it seems that they only work in combination with type definition in the object model.
Next on my way through the possible solutions, I accepted the truth and created a deserializer for Object because that's the only type, I am pretty sure about ;)
What I was missing then was an option to defer parsing for "not my type" back to the mapper.
Otherwise I would have to write Jackson's mapping for simple types, list, maps... again but bad.
Yes, I could create another mapper in there but it wouldn't know the configuration of the "original" mapper.
The only way, I got this working somehow was to define the target map like this:
public class DataValues {
#JsonCreator
public DataValues(Map<String, Object> targetMap) {
this.targetMap = targetMap.entrySet().stream().collect(Collectors.toMap(
Map.Entry::getKey,
map -> {
Object newValue = map.getValue();
newValue = optionalConversion(newValue);
return newValue;
}));
}
}
and decide on the provided map if I want to convert it or if it's a nested map with plain values (or a list, or another map).
I think we can agree that this approach is not the optimal solution, to describe it positively.
My current mood is that maybe I am just missing a bit on the JsonTypeInfo or there is a way to delegate the mapping in an Object based deserializer that I haven't found yet.
Or an (to me) unknown third option that is so simple that I never thought about it.
My solution now is pretty straight-forward and simple as it (might) could be.
I think the missing bit for me was jsonParser.getCodec() to delegate the "known unknown" types.
Also a benefit of a deserializer in my case is, that I can filter Jackson-mappable types upfront and only allow the simple types I want to support.
private static class ParameterDeserializer extends JsonObjectDeserializer<Object> {
#Override
protected Object deserializeObject(JsonParser jsonParser, DeserializationContext context, ObjectCodec codec, JsonNode tree) throws IOException {
if (tree.isValueNode()) {
if (tree.isTextual()) {
return tree.asText();
}
if (tree.isFloatingPointNumber()) {
return tree.asDouble();
}
if (tree.isBoolean()) {
return tree.asBoolean();
}
if (tree.isInt()) {
return tree.asInt();
}
if (tree.isNumber()) {
return tree.asLong();
}
}
if (tree.isContainerNode()) {
if (tree.getNodeType().equals(JsonNodeType.ARRAY)) {
return jsonParser.getCodec().treeToValue(tree, List.class);
}
if (tree.getNodeType().equals(JsonNodeType.OBJECT)) {
JsonNode customType = tree.get("type");
if (customType != null) {
// do custom conversion
}
return jsonParser.getCodec().treeToValue(tree, Map.class);
}
}
throw new IllegalArgumentException("Cannot parse %s as a valid parameter type".formatted(tree));
}
}

MapStruct - Map Generic List to Non-Generic List containing different types

I am attempting to use MapStruct to convert between 2 internal models. These models are generated from the same specification and represent a large tree-like structure that is constantly being added to. The goal of using MapStruct is to have an efficient, low (non-generated) code way of performing this conversion that stays up to date with additions to the specification. As an example, my models would look like:
package com.mycompany.models.speca;
public class ModelSpecA {
private String name;
private int biggestNumberFound;
private com.mycompany.models.speca.InternalModel internalModel;
private List<com.mycompany.models.speca.InternalModel> internalModelList;
}
package com.mycompany.models.specb;
public class ModelSpecB {
private String name;
private int biggestNumberFound;
private com.mycompany.models.specb.InternalModel internalModel;
private List internalModelList;
}
with all of the expected getters and setters and no-arg constructors.
MapStruct is able to generate code for the mapping extremely easily with the code looking like:
interface ModelSpecMapper {
ModelSpecB map(ModelSpecA source);
}
From unit testing and inspecting the generated code, the mapping is accurate and complete except in one regard: the mapping of the internalModelList member in each class. The generated code looks like the following:
...
if (sourceInternalModelList != null) {
specBTarget.setInternalModelList( specASource.getInternalModelList() );
}
...
I.e. It is mapping from the generic List<com.mycompany.models.speca.InternalModel> to the non-generic List without doing model conversion. This passes at compile time and runtime in unit tests, but will cause errors in later code when we expect to be able to cast to the SpecB version of the model.
So far, I've investigated if it is possible to force a mapping of the parameterized type in the source to its corresponding type without using expensive reflection operations, which would eliminate the gains from using MapStruct as a solution. This is my first experience with MapStruct, so there may be an obvious solution I am simply unaware of. Adding an explicit mapping is infeasible as I need this to be forward compatible with future additions to the model including new Lists.
TLDR; How do I use MapStruct to convert the contents of a generic List to a non-generic List? E.g. List<com.mycompany.a.ComplexModel> --> List whose members are of type com.mycompany.b.ComplexModel.
Based on suggestions by #chrylis -cautiouslyoptimistic-, I managed to successfully accomplish the mapping by using Jackson to perform the mapping directly from type to type, but that is tangential to the MapStruct problem. I was able to accomplish the stated goal of mapping a generic list to a non-generic list by adding a default mapping to my MapStruct mapper:
/**
* Map a generic List which contains object of any type to a non-generic List which will contain objects
* of the resulting mapping.
* E.g. It maps a generic list of T to a non-generic list of contents mapped from T.
* #param source Source generic List to map from.
* #return A non-generic List whose contents are the contents of <i>source</i> with mapping implementation applied.
* #param <T>
*/
default <T> List mapGenericToNonGeneric(List<T> source) {
if (source == null) {
return null;
}
if (source.isEmpty()) {
return new LinkedList();
}
// Handle the most common known cases as an optimization without expensive reflection.
final Class<?> objectClass = source.get(0).getClass();
if (ClassUtils.isPrimitiveOrWrapper(objectClass)) {
return new LinkedList(source);
}
if (String.class.equals(objectClass)) {
return new LinkedList(source);
}
try {
Method mapperMethod = Stream.of(this.getClass().getDeclaredMethods())
.map(method -> {
Parameter[] params = method.getParameters();
// If this method is a mapper that takes the type of our list contents
if (params.length == 1 && params[0].getParameterizedType().equals(objectClass)) {
return method;
}
return null;
})
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
if (mapperMethod != null) {
final List result = new LinkedList();
for (T sourceObject : source) {
result.add(mapperMethod.invoke(this, sourceObject));
}
log.info("Executed slow generic list conversion for type {}", objectClass.getName());
return result;
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
From inspecting the generated code and adding assertions to the type of each collection contents, this is passing my property-based testing suite. It still makes use of reflection to determine the parameterized type but is able to handle arbitrary additions to the model and outperforms the previous Jackson solution substantially.

Initiate ArrayList of dynamic type

I have an HTTP request handler that returns deserialized JSON an Object, which is derived from an abstract Request and then cast to the correct class. I'm having some issues making this handler return a List though.
public class ListMyResource extends AbstractRequest
{
public boolean isCollection;
public ListTransactions()
{
this.isCollection = true;
}
public final RequestMethod REQUEST_METHOD = RequestMethod.GET;
public final String URL_METHOD = "";
public Class<ArrayList<MyResource>> getResourceClass()
{
return new ArrayList<MyResource>().getClass();
}
}
public Object getDeserializedResponse()
{
Response response = new Response(this.request, true);
try
{
if (this.request.isCollection())
{
List<this.request.getResourceClass()> list = new ArrayList<this.request.getResourceClass()>();
listType = new TypeToken<ArrayList<AbstractObject>>() { }.getType();
response.setData(deserialize.fromJson(this.getResponse(), listType));
}
else
{
response.setData(deserialize.fromJson(this.getResponse(), this.request.getClazz()));
}
}
catch (JsonSyntaxException jse)
{
MyLibrary.LOG.error("Could not parse JSON", jse);
response.setRequestWasSuccessfull(false);
}
return response;
}
The above code works fine if isCollection() returns false and the method only has to come up with a single deserialized object, but it doesn't work for collections as I can't put the result from getResourceClass() in the <> from the List. That results in Identifier expected. How can I approach this so I achieve the desired result?
ArrayList<this.request.getResourceClass()>
This cannot work. Java type parameters must be compile-time "constants" (I mean, something known to the compiler). So,
List<String> strings
is a valid syntax for the type parameters, but
List<some.runtime.expression.here()>
is not. Next thing, I would strongly recommend you not to use Class<?> to pass data type information. Note that Class<?> holds information about a real type in your system. Consider you want to have a list of strings, a list of integers and a list of booleans types. You can't do ArrayList<String>.class -- it's an illegal expression in Java, because actual type parameters are not a part of class information. Can you subclass ArrayList with something like extends ArrayList<String> and so on? You can but you shouldn't. What if the class to subclass is final or you're going to use LinkedList? Some sort of code bloat, isn't it?
Class is java.lang.reflect.Type, and Gson requires an instance of the latter to be passed to the fromJson() method. What if you construct it yourself? Gson provides a convenient mechanism to construct java.lang.reflect.Type and java.lang.reflect.ParameterizedType (the latter is used for collections very intensively in Gson by the way, see more for Gson TypeTokens). The are two ways:
TypeToken.getParameterized(rawType, typeParameter1, typeParameter2)
For example, TypeToken.getParameterized(List.class, String.class).getType() will return a ParameterizedType instance as if it you could write List<String>.class. This is a truly dynamic approach, and you can pass some runtime execution results to the getParameterized() method.
TypeToken subclassing
The trick here is that TypeToken is an abstract class and it can be parameterized, letting Gson analyze a usually anonymous class for the actual parameters at runtime and let the getType() method return a compile-time composed type: new TypeToken<List<String>>(){}.getType() (subclasses can store information about their super classes parameterization, and Gson uses it at runtime). Note that getRawType returns List.class only - this is all just how Java generics are implemented since Class cannot store actual type parameters (read more for Java generics and erasure).
Having this vague explanation in mind, just refactor your getDeserializedResponse() method making a request return java.lang.reflect.Type rather than Class<?>. I even think that you can remove isCollection from that method and just let Gson do it all itself: Gson can distinguish between List<String> and List<Integer> types.

java: How can I do dynamic casting of a variable from one type to another?

I would like to do dynamic casting for a Java variable, the casting type is stored in a different variable.
This is the regular casting:
String a = (String) 5;
This is what I want:
String theType = 'String';
String a = (theType) 5;
Is this possible, and if so how? Thanks!
Update
I'm trying to populate a class with a HashMap that I received.
This is the constructor:
public ConnectParams(HashMap<String,Object> obj) {
for (Map.Entry<String, Object> entry : obj.entrySet()) {
try {
Field f = this.getClass().getField(entry.getKey());
f.set(this, entry.getValue()); /* <= CASTING PROBLEM */
} catch (NoSuchFieldException ex) {
log.error("did not find field '" + entry.getKey() + '"');
} catch (IllegalAccessException ex) {
log.error(ex.getMessage());
}
}
}
The problem here is that some of the class' variables are of type Double, and if the number 3 is received it sees it as Integer and I have type problem.
Yes it is possible using Reflection
Object something = "something";
String theType = "java.lang.String";
Class<?> theClass = Class.forName(theType);
Object obj = theClass.cast(something);
but that doesn't make much sense since the resulting object must be saved in a variable of Object type. If you need the variable be of a given class, you can just cast to that class.
If you want to obtain a given class, Number for example:
Object something = new Integer(123);
String theType = "java.lang.Number";
Class<? extends Number> theClass = Class.forName(theType).asSubclass(Number.class);
Number obj = theClass.cast(something);
but there is still no point doing it so, you could just cast to Number.
Casting of an object does NOT change anything; it is just the way the compiler treats it.
The only reason to do something like that is to check if the object is an instance of the given class or of any subclass of it, but that would be better done using instanceof or Class.isInstance().
Update
according your last update the real problem is that you have an Integer in your HashMap that should be assigned to a Double. What you can do in this case, is check the type of the field and use the xxxValue() methods of Number
...
Field f = this.getClass().getField(entry.getKey());
Object value = entry.getValue();
if (Integer.class.isAssignableFrom(f.getType())) {
value = Integer.valueOf(((Number) entry.getValue()).intValue());
} else if (Double.class.isAssignableFrom(f.getType())) {
value = Double.valueOf(((Number) entry.getValue()).doubleValue());
} // other cases as needed (Long, Float, ...)
f.set(this, value);
...
(not sure if I like the idea of having the wrong type in the Map)
You'll need to write sort of ObjectConverter for this. This is doable if you have both the object which you want to convert and you know the target class to which you'd like to convert to. In this particular case you can get the target class by Field#getDeclaringClass().
You can find here an example of such an ObjectConverter. It should give you the base idea. If you want more conversion possibilities, just add more methods to it with the desired argument and return type.
Regarding your update, the only way to solve this in Java is to write code that covers all cases with lots of if and else and instanceof expressions. What you attempt to do looks as if are used to program with dynamic languages. In static languages, what you attempt to do is almost impossible and one would probably choose a totally different approach for what you attempt to do. Static languages are just not as flexible as dynamic ones :)
Good examples of Java best practice are the answer by BalusC (ie ObjectConverter) and the answer by Andreas_D (ie Adapter) below.
That does not make sense, in
String a = (theType) 5;
the type of a is statically bound to be String so it does not make any sense to have a dynamic cast to this static type.
PS: The first line of your example could be written as Class<String> stringClass = String.class; but still, you cannot use stringClass to cast variables.
You can do this using the Class.cast() method, which dynamically casts the supplied parameter to the type of the class instance you have. To get the class instance of a particular field, you use the getType() method on the field in question. I've given an example below, but note that it omits all error handling and shouldn't be used unmodified.
public class Test {
public String var1;
public Integer var2;
}
public class Main {
public static void main(String[] args) throws Exception {
Map<String, Object> map = new HashMap<String, Object>();
map.put("var1", "test");
map.put("var2", 1);
Test t = new Test();
for (Map.Entry<String, Object> entry : map.entrySet()) {
Field f = Test.class.getField(entry.getKey());
f.set(t, f.getType().cast(entry.getValue()));
}
System.out.println(t.var1);
System.out.println(t.var2);
}
}
You can write a simple castMethod like the one below.
private <T> T castObject(Class<T> clazz, Object object) {
return (T) object;
}
In your method you should be using it like
public ConnectParams(HashMap<String,Object> object) {
for (Map.Entry<String, Object> entry : object.entrySet()) {
try {
Field f = this.getClass().getField(entry.getKey());
f.set(this, castObject(entry.getValue().getClass(), entry.getValue()); /* <= CASTING PROBLEM */
} catch (NoSuchFieldException ex) {
log.error("did not find field '" + entry.getKey() + '"');
} catch (IllegalAccessException ex) {
log.error(ex.getMessage());
}
}
}
It works and there's even a common pattern for your approach: the Adapter pattern. But of course, (1) it does not work for casting java primitives to objects and (2) the class has to be adaptable (usually by implementing a custom interface).
With this pattern you could do something like:
Wolf bigBadWolf = new Wolf();
Sheep sheep = (Sheep) bigBadWolf.getAdapter(Sheep.class);
and the getAdapter method in Wolf class:
public Object getAdapter(Class clazz) {
if (clazz.equals(Sheep.class)) {
// return a Sheep implementation
return getWolfDressedAsSheep(this);
}
if (clazz.equals(String.class)) {
// return a String
return this.getName();
}
return null; // not adaptable
}
For you special idea - that is impossible. You can't use a String value for casting.
Your problem is not the lack of "dynamic casting". Casting Integer to Double isn't possible at all. You seem to want to give Java an object of one type, a field of a possibly incompatible type, and have it somehow automatically figure out how to convert between the types.
This kind of thing is anathema to a strongly typed language like Java, and IMO for very good reasons.
What are you actually trying to do? All that use of reflection looks pretty fishy.
Don't do this. Just have a properly parameterized constructor instead. The set and types of the connection parameters are fixed anyway, so there is no point in doing this all dynamically.
For what it is worth, most scripting languages (like Perl) and non-static compile-time languages (like Pick) support automatic run-time dynamic String to (relatively arbitrary) object conversions. This CAN be accomplished in Java as well without losing type-safety and the good stuff statically-typed languages provide WITHOUT the nasty side-effects of some of the other languages that do evil things with dynamic casting. A Perl example that does some questionable math:
print ++($foo = '99'); # prints '100'
print ++($foo = 'a0'); # prints 'a1'
In Java, this is better accomplished (IMHO) by using a method I call "cross-casting".
With cross-casting, reflection is used in a lazy-loaded cache of constructors and methods that are dynamically discovered via the following static method:
Object fromString (String value, Class targetClass)
Unfortunately, no built-in Java methods such as Class.cast() will do this for String to BigDecimal or String to Integer or any other conversion where there is no supporting class hierarchy. For my part, the point is to provide a fully dynamic way to achieve this - for which I don't think the prior reference is the right approach - having to code every conversion. Simply put, the implementation is just to cast-from-string if it is legal/possible.
So the solution is simple reflection looking for public Members of either:
STRING_CLASS_ARRAY = (new Class[] {String.class});
a) Member member = targetClass.getMethod(method.getName(),STRING_CLASS_ARRAY);
b) Member member = targetClass.getConstructor(STRING_CLASS_ARRAY);
You will find that all of the primitives (Integer, Long, etc) and all of the basics (BigInteger, BigDecimal, etc) and even java.regex.Pattern are all covered via this approach. I have used this with significant success on production projects where there are a huge amount of arbitrary String value inputs where some more strict checking was needed. In this approach, if there is no method or when the method is invoked an exception is thrown (because it is an illegal value such as a non-numeric input to a BigDecimal or illegal RegEx for a Pattern), that provides the checking specific to the target class inherent logic.
There are some downsides to this:
1) You need to understand reflection well (this is a little complicated and not for novices).
2) Some of the Java classes and indeed 3rd-party libraries are (surprise) not coded properly. That is, there are methods that take a single string argument as input and return an instance of the target class but it isn't what you think... Consider the Integer class:
static Integer getInteger(String nm)
Determines the integer value of the system property with the specified name.
The above method really has nothing to do with Integers as objects wrapping primitives ints.
Reflection will find this as a possible candidate for creating an Integer from a String incorrectly versus the decode, valueof and constructor Members - which are all suitable for most arbitrary String conversions where you really don't have control over your input data but just want to know if it is possible an Integer.
To remedy the above, looking for methods that throw Exceptions is a good start because invalid input values that create instances of such objects should throw an Exception. Unfortunately, implementations vary as to whether the Exceptions are declared as checked or not. Integer.valueOf(String) throws a checked NumberFormatException for example, but Pattern.compile() exceptions are not found during reflection lookups. Again, not a failing of this dynamic "cross-casting" approach I think so much as a very non-standard implementation for exception declarations in object creation methods.
If anyone would like more details on how the above was implemented, let me know but I think this solution is much more flexible/extensible and with less code without losing the good parts of type-safety. Of course it is always best to "know thy data" but as many of us find, we are sometimes only recipients of unmanaged content and have to do the best we can to use it properly.
Cheers.
So, this is an old post, however I think I can contribute something to it.
You can always do something like this:
package com.dyna.test;
import java.io.File;
import java.lang.reflect.Constructor;
public class DynamicClass{
#SuppressWarnings("unchecked")
public Object castDynamicClass(String className, String value){
Class<?> dynamicClass;
try
{
//We get the actual .class object associated with the specified name
dynamicClass = Class.forName(className);
/* We get the constructor that received only
a String as a parameter, since the value to be used is a String, but we could
easily change this to be "dynamic" as well, getting the Constructor signature from
the same datasource we get the values from */
Constructor<?> cons =
(Constructor<?>) dynamicClass.getConstructor(new Class<?>[]{String.class});
/*We generate our object, without knowing until runtime
what type it will be, and we place it in an Object as
any Java object extends the Object class) */
Object object = (Object) cons.newInstance(new Object[]{value});
return object;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public static void main(String[] args)
{
DynamicClass dynaClass = new DynamicClass();
/*
We specify the type of class that should be used to represent
the value "3.0", in this case a Double. Both these parameters
you can get from a file, or a network stream for example. */
System.out.println(dynaClass.castDynamicClass("java.lang.Double", "3.0"));
/*
We specify a different value and type, and it will work as
expected, printing 3.0 in the above case and the test path in the one below, as the Double.toString() and
File.toString() would do. */
System.out.println(dynaClass.castDynamicClass("java.io.File", "C:\\testpath"));
}
Of course, this is not really dynamic casting, as in other languages (Python for example), because java is a statically typed lang. However, this can solve some fringe cases where you actually need to load some data in different ways, depending on some identifier. Also, the part where you get a constructor with a String parameter could be probably made more flexible, by having that parameter passed from the same data source. I.e. from a file, you get the constructor signature you want to use, and the list of values to be used, that way you pair up, say, the first parameter is a String, with the first object, casting it as a String, next object is an Integer, etc, but somehwere along the execution of your program, you get now a File object first, then a Double, etc.
In this way, you can account for those cases, and make a somewhat "dynamic" casting on-the-fly.
Hope this helps anyone as this keeps turning up in Google searches.
Try this for Dynamic Casting. It will work!!!
String something = "1234";
String theType = "java.lang.Integer";
Class<?> theClass = Class.forName(theType);
Constructor<?> cons = theClass.getConstructor(String.class);
Object ob = cons.newInstance(something);
System.out.println(ob.equals(1234));
I recently felt like I had to do this too, but then found another way which possibly makes my code look neater, and uses better OOP.
I have many sibling classes that each implement a certain method doSomething(). In order to access that method, I would have to have an instance of that class first, but I created a superclass for all my sibling classes and now I can access the method from the superclass.
Below I show two ways alternative ways to "dynamic casting".
// Method 1.
mFragment = getFragmentManager().findFragmentByTag(MyHelper.getName(mUnitNum));
switch (mUnitNum) {
case 0:
((MyFragment0) mFragment).sortNames(sortOptionNum);
break;
case 1:
((MyFragment1) mFragment).sortNames(sortOptionNum);
break;
case 2:
((MyFragment2) mFragment).sortNames(sortOptionNum);
break;
}
and my currently used method,
// Method 2.
mSuperFragment = (MySuperFragment) getFragmentManager().findFragmentByTag(MyHelper.getName(mUnitNum));
mSuperFragment.sortNames(sortOptionNum);
Just thought I would post something that I found quite useful and could be possible for someone who experiences similar needs.
The following method was a method I wrote for my JavaFX application to avoid having to cast and also avoid writing if object x instance of object b statements every time the controller was returned.
public <U> Optional<U> getController(Class<U> castKlazz){
try {
return Optional.of(fxmlLoader.<U>getController());
}catch (Exception e){
e.printStackTrace();
}
return Optional.empty();
}
The method declaration for obtaining the controller was
public <T> T getController()
By using type U passed into my method via the class object, it could be forwarded to the method get controller to tell it what type of object to return. An optional object is returned in case the wrong class is supplied and an exception occurs in which case an empty optional will be returned which we can check for.
This is what the final call to the method looked like (if present of the optional object returned takes a Consumer
getController(LoadController.class).ifPresent(controller->controller.onNotifyComplete());

How to design an object which can be one of two types?

I'm reading a HTTP POST and the body of the HTTP request can be either JSON or XML.
Now I've delegated the reading to a special utility class.
interface HttpUtils
{
BodyWrapper parseBody( HttpServletRequest req );
}
interface BodyWrapper
{
boolean isXML(); // 1
boolean isJSON(); // 2
String body(); // 3
}
I hate the fact that BodyWrapper has methods (1 & 2) to identify its type. Perhaps I should use inheritance. If I do that, I will need to do an instanceof to find out what is being returned by HttpUtils.parseBody(..)
Ideally I would also want the body() method to return either a JSONObject or an DOM node. How would I do that?
Don't ask your objects for information, and then make decisions on what they tell you. Make your objects do the work for you. That is, don't do this:
if (body.isXML()) {
// do XML stuff
}
else if (body.isJSON()) {
// do JSON stuff
}
It's a maintenance headache. Do something like this instead (the BodyWrapper implementations would created using an abstract factory method or similar)
public interface BodyWrapper {
Object doStuff();
}
public class DOMBodyWrapper implements BodyWrapper {
public Object doStuff() {
}
}
public class JSONBodyWrapper implements BodyWrapper {
public Object doStuff() {
// do something and return a success/failure result. I've
// deliberately not defined what this object is....
}
}
and then:
// get the body via a factory or similar
body.doStuff();
That way, something creates the appropriate BodyWrapper implementation, and then instead of asking it what type it is, you just use it. Note that the BodyWrapper isn't returning different types of internal structures, because it (perhaps an abstract base class) is doing the work for you.
First off, HttpUtils is way to generic a name. I'd go for HttpRequestParser or something. You'll also need a factory which will create appropriate implementation based on content-type of a request (XmlRequestParser or JsonRequestParser).
As far as parsing goes, I'd recommend to parse both XML and JSON to some arbitrary internal representation (IR), so that your code higher up the stack will not be concerned with such details. An IR can be an XML document, or some object graph.
What on earth is BodyWrapper for? Shouldn't parseBody just return the de-seriealized object? This could be a model object or it could just be a bag of values (dictionary / map / hashtable).
So, parseBody will need to check the type of the POST and then deserialize. What data are you expecting? The result should be a type that represents the actual data you want the client to post in a java sort of way, irregardless of how it was posted (jason / xml)
JSONObject and DOM nodes are unrelated to each other, inheritance wise. This means that in order to overload on the return type it would have to return object. This is a nasty code smell since you would probably then have to use introspection to figure out what was returned. Generally in this situation, you should be using a virtual method on the object (the body) which is able to act on the body in the correct fashion depending on what it actually is.
Just to give you some more food for thought, a variation of the Visitor pattern where the data types are not related by interitance could help you out here.
To be honest though, it could also turn out to be overkill in this particular case depending on your actual use case(s).
Here's some pseudo-code:
interface BodyTypesVisitor
{
void visit( DOMNode domNode );
void visit( JSONObject jsonObject );
}
interface BodyWrapper
{
void accept( BodyTypesVisitor );
}
interface HttpUtils
{
BodyWrapper parseBody( HttpServletRequest req );
}
class DOMVisitor implements BodyTypesVisitor
{
void visit( DOMNode domNode ) { /* do something useful with domNode */ }
void visit( JSONObject jsonObject ) { /* ignore */ }
}
class DOMBody implements BodyWrapper
{
...
void accept( BodyTypesVisitor visitor )
{ visitor.visit( this->domNode ); }
private DOMNode domNode;
}
...
// Process DOM
BodyWrapper wrapper = <some HttpUtils implementation that creates a DOMBody>
DOMVisitor visitor = new DOMVisitor();
wrapper.accept(visitor);
The Visitor pattern is generally useful if you have a distinct and relatively static set of "data types" that you want to process in several different ways.
Abstraction seems difficult alt this level. What do you do with the JSONObject or DOM returned as body? Often it is more easy to go one step further. Is it possible to transform both to the same Java structure? Depending on the content type, create the JSOn or DOM implementation of your body parser and use the resulting java structure created by the parser in the code working on the body. If neeeded (to create the right answer format), you can make the original content type available from the answer (getMimeType() or something like that).

Categories