How to use a Superclass and Subclasses in Java with shared methods - java

I have a superclass called Currency and I want to have a bunch of different subclasses that inherit this super class, e.g. USD, GBP, YEN, etc.
Each of these subclasses have the same attributes and methods. The methods will return the same types of value, but the body of the methods will need to be slightly different. Here's an example (I am using API calls to get the amount of each currency that I own):
public class USD extends Currency {
public String symbol;
public String holdings;
public String bankAccountId; // Each currency has it's own account
public float getHoldings(String apiKey) {
HttpClient httpClient = HttpClient.newHttpClient();
URI uri = new URIBuilder(apiBaseurl)
.addParameter("module", "account")
.addParameter("action", "tokenbalance")
.addParameter("accountid", this.bankAccountId)
.addParameter("apikey", apiKey)
.build();
HttpRequest getHoldingsRequest = HttpRequest.newBuilder()
.uri(uri)
.GET()
.build();
HttpResponse<String> response = httpClient.send(getHoldingsRequest, BodyHandlers.ofString());
ObjectNode node = new ObjectMapper().readValue(response.body(), ObjectNode.class);
return node.get("result").asFloat();
}
}
My main problem is that I don't want to repeat this getHoldings() method in each subclass, so I decided to try and put it into the Currency superclass, but then I have 2 new problems:
I can't use this.bankAccountId in the method (each currency is held in an individual account, specific to that currency and I'd prefer to have the String bankAccountId as an attribute for the specific currency subclass).
I can't loop through each currency and use the getHoldings() method on each one, like this:
Portfolio portfolio = new Portfolio();
String myApiKey = "duivbncvavsuivavcshinseo" // Some apiKey here
portfolio.setOwnedCurrencies(Arrays.asList(
new USD(),
new GBP(),
new YEN()
));
for (Currency currency : portfolio.getOwnedCurrencies()) {
System.out.println(currency.getHoldings(myApiKey));
}
I've looked at using Generics so I can have Currency<USD>, but I can't quite figure out how to use them correctly in this case. I also feel like I'm missing something pretty basic/easy here, but I've been staring at this problem for so long, I just can't see it.
EDIT: I should've mentioned, each Currency subclass has other unique values, so each subclass has the same attributes, but the attributes will have different, not just the bankAccountId.

Why not use the id through sending it into the method as Ann argument if needed, too, processing of methods by "superclasses extended from" can be package private (should not be public) at worst protected methods (unless you want other classes to be able to access directly), and you could return an array or a Vector if you need to bring back multiple result from the process e.g. bankid and holdings answer.

Related

How to write custom casting method in Java

I have a Java class that has a few members. I want to write a custom cast for it. I was wondering how is it possible to do so?
Let's assume the class is as follows:
class Person {
private int age;
private float weight;
// getters and setters and etc
}
I would like the int cast to return the member age of an object, and the float cast to return the weight of an object.
For instance:
public class Main {
public static void main(String[] args) {
// create an object
Person P = new Person();
P.setAge(21);
P.setWeight(88.0);
// case 1: casting object to an existing data type
int personAge = (int) P; // would return the age
float personWeight = (float) P; // would return the weight
// case 2: casting an existing data type to an object
Person P2 = (Person) personAge; // this would create an instance of the object whose age is assigned and weight is not assigned
}
}
I was wondering if it is possible to do the opposite. In particular, casting int to Person would return an instance of Person that its age is assigned and similarly for float.
I know this question may not have an answer. But because I did not find any useful results in my search, I decided to ask it.
P.S. I understand that for a String, the toString method would take care of case 1.
You can't overload the cast operator. Java doesn't support it and probably never will.
To convert a single value to an instance of the desired class, we use static factory methods.
public static Person fromAge(int age) {
return new Person(age);
}
They often return a partially constructed object. In the snippet above, a newly constructed person has only age set: other fields will have their default values.
To do the opposite, we use getters.
public int getAge() {
return age;
}
However, since toString is already there, it makes sense to add other data types as well.
toInt makes no sense when it's applied to me (as an instance of the Person class). It could be my height, my weight, my age, a number of times I went to a bathroom today, etc. I can't represent myself by one int number, neither can a large majority of classes.
On the other hand, toString can do this job pretty well: I can give you (read return) a summary of my hobbies, my biometric information, even my picture. Or I can leave it to the default implementation, which still would satisfactorily represent an object.
You wouldn't use a cast for this just write methods in your Person class to get those values.
public int getAge()
{
return age;
}
etc.
So I've only done this once and I'm unsure whether the approach I did is the appropriate way.
But my approach was a method called typeConverter, which i would give an object as parameter, then you could take that parameter and look what object type it is and then create a new Person, with your value.
Although this approach could cause problems, when your class would have two integer fields. But I think you could find a solution for this, by giving it another parameter that defines, which field you'd want to convert it to.
I'm really sorry for my poor english, but I hope you get the principle.

Creating an object from class A...Z (scalable) depending on the value of a string

Is this possible? Could I instance an object from one class or another depending on the value of a string?
I have a code like this:
public Map<Language, IConverter> converters;
// ...
public IConverter buildConverter(Language lang) {
IConverter converter = new ???(buildMap(lang)); <---- Problem here
converters.put(lang, converter);
}
public Map<Integer, String> buildMap(Language lang) {
// ...
}
Where Language is a bean class containing a string which identifies a language and IConverter is an interface implemented by several (undefined amount) concrete Converter.
Do I need to add an if clause per supported Converter? Is there anyway to idenfity which string belongs to which class, maybe with a Map or something like that?
I may drop the Language class, because it is kind of shallow and can't see it scalating.
EDIT
I ended using Jesper's answer, I had to adapt my Language class for it to contain the full language name, and concatenating the package name, the languagename and "Converter".
Boy, is Reflection scary at first, so many, many Exceptions.
If you have the name of the class in a string, you can create a new instance of it using reflection. For example:
String className = "com.mycompany.SomeConverter";
// Creates an instance of the class by using the no-args constructor
IConverter converter = (IConverter) Class.forName(className).newInstance();
If you want to use a specific constructor with arguments:
// For example, look for a constructor that takes one argument, a String
Constructor constr = Class.forName(className).getConstructor(String.class);
// Create a new instance, passing "Hello" as the argument
IConverter converter = (IConverter) constr.newInstance("Hello");
may be you need something very similar to this.
i guess you mean this
Constructor constr = Class.forName("com.yourpackage.converter" + lang.getYourString()).getConstructor(buildMap_function_returned_class.class);
IConverter converter = (IConverter) constr.newInstance(buildMap(lang));

How can I map a String to a function in Java?

Currently, I have a bunch of Java classes that implement a Processor interface, meaning they all have a processRequest(String key) method. The idea is that each class has a few (say, <10) member Strings, and each of those maps to a method in that class via the processRequest method, like so:
class FooProcessor implements Processor
{
String key1 = "abc";
String key2 = "def";
String key3 = "ghi";
// and so on...
String processRequest(String key)
{
String toReturn = null;
if (key1.equals(key)) toReturn = method1();
else if (key2.equals(key)) toReturn = method2();
else if (key3.equals(key)) toReturn = method3();
// and so on...
return toReturn;
}
String method1() { // do stuff }
String method2() { // do other stuff }
String method3() { // do other other stuff }
// and so on...
}
You get the idea.
This was working fine for me, but now I need a runtime-accessible mapping from key to function; not every function actually returns a String (some return void) and I need to dynamically access the return type (using reflection) of each function in each class that there's a key for. I already have a manager that knows about all the keys, but not the mapping from key to function.
My first instinct was to replace this mapping using if-else statements with a Map<String, Function>, like I could do in Javascript. But, Java doesn't support first-class functions so I'm out of luck there. I could probably dig up a third-party library that lets me work with first-class functions, but I haven't seen any yet, and I doubt that I need an entire new library.
I also thought of putting these String keys into an array and using reflection to invoke the methods by name, but I see two downsides to this method:
My keys would have to be named the same as the method - or be named in a particular, consistent way so that it's easy to map them to the method name.
This seems WAY slower than the if-else statements I have right now. Efficiency is something of a concern because these methods will tend to get called pretty frequently, and I want to minimize unnecessary overhead.
TL; DR: I'm looking for a clean, minimal-overhead way to map a String to some sort of a Function object that I can invoke and call (something like) getReturnType() on. I don't especially mind using a 3rd-party library if it really fits my needs. I also don't mind using reflection, though I would strongly prefer to avoid using reflection every single time I do a method lookup - maybe using some caching strategy that combines the Map with reflection.
Thoughts on a good way to get what I want? Cheers!
There aren't any first-class standalone functions, but you can do what you want with an interface. Create an interface that represents your function. For example, you might have the following:
public interface ComputeString
{
public String invoke();
}
Then you can create a Map<String,ComputeString> object like you want in the first place. Using a map will be much faster than reflection and will also give more type-safety, so I would advise the above.
While you can't have first class functions, there are anonymous classes which can be based on an interface:
interface ProcessingMethod {
String method();
}
Map<String, ProcessingMethod> methodMap = new HashMap<String, ProcessingMethod>();
methodMap.put("abc", new ProcessingMethod() {
String method() { return "xyz" }
});
methodMap.put("def", new ProcessingMethod() {
String method() { return "uvw" }
});
methodMap.get("abc").method();
Or you could use Scala :-)
Couldn't you do String to Method? Then you can cache the methods you need to execute.
This example uses an enum of named functions and an abstract FunctionAdapter to invoke functions with a variable number of homogeneous parameters without reflection. The lookup() function simply uses Enum.valueOf, but a Map might be worth it for a large number of functions.
As you've noticed, you can do what you want using the Reflection API, but you loose some benefits of the Java compiler, on top of the issues you've already come up with. Would wrapping your Strings in an object and using the Visitor pattern solve your issue? Each StringWrapper would only accept a Visitor that has the right method, or something along those lines.
Use a Map where the key is a string and the value is an object that implements an interface containing method(). That way you can get the object containing the method you want out of the map. Then just call that method on the object. For example:
class FooProcessor implements Processor{
Map<String, FooMethod> myMap;
String processRequest(String key){
FooMethod aMethod = myMap.getValue(key);
return aMethod.method();
}
}
What about Method class from the reflection API? You can find methods of a class based on name, parameters, or return type. Then you just call Method.invoke(this, parameters).
That's pretty much the same as a Map from JavaScript you are talking about.
public class CarDetailsService {
private final CarRepository carRepository;
private final Map<String, Function<CarDTO, String>> carColumnMapper = new HashMap<>();
public ApplicationDetailsServiceImpl(CarRepository carRepository) {
this.carRepository = carRepository;
//---- Initialise all the mappings ------- //
carColumnMapper.put("BRAND", CarDTO::getBrandName);
carColumnMapper.put("MILEAGE", CarDTO::getMileage);
}
public Map<String, List<CarDTO>> getListOfCars(String groupBy) {
return carRepository.findAll()
.stream()
.map(toCarDTO)
.collect(groupingBy(carColumnMapper.get(groupBy.toUpperCase())));
}
Function<CarDetails, CarDTO> toCarDTO = (carDetails) -> CarDTO
.builder()
.brand(carDetails.getBrand())
.engineCapacity(carDetails.getEngineCapacity())
.mileage(carDetails.getMileage())
.fuel(carDetails.getFuel())
.price(carDetails.getPrice())
.build();
}

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