Get return statements in a java method - java

How can I get all possible return values of a method in java?
Example:
Object onEvent() {
if (condition) {
return "a";
}
if (condition2) {
return "b";
}
if (condition3) {
return "c";
}
}
I need something like this:
String[] returns = Utils.getReturnStatements("object.onEvent()");
returns = ["a", "b", "c"]

You can only retrieve the method signature, which in this case would be Object as the return type.
To get the any more details you need to either statically analyze the source code or return a type such as an enum.

If you only need to analyse simple methods that return constant values such as the one in your example, then you can do this relatively easily via a static analysis using ASM or a similar bytecode toolkit.
For methods matching the structure of your example (i.e that only directly return constants) you just need to look for the pattern
LDC ???
ARETURN
And collect the constants loaded with LDC. This would be very straightforward.
If the methods can be more complex, e.g if they return values assigned to variables, then you will need to perform a flow analysis. This is much more work, but ASM provides support.
If the methods you are analysing return values other than simple constants then it will be incredibly difficult/impossible to do this via static analysis.

You can't do such a thing in Java, but you can do something like this:
Object onEvent() {
List<String> list = new ArrayList<String>();
if (condition) {
list.add("a");
}
if (condition2) {
list.add("b");
}
if (condition3) {
list.add("c");
}
return list.toArray();
}
And then:
String[] returns = (String[])MyObj.onEvent();

First remove multiple returns:
Also to get all return types just pass a List of object to your method and change the onEvent code like this:
Object onEvent(List<Object> rets) {
String ret = "";
rets.add("a");
rets.add("b");
rets.add("c");
if (condition) {
ret = "a";
}
if (condition2) {
ret = "b";
}
if (condition3) {
ret = "c";
}
return ret;
}
Make a call to onEvent like this:
List<Object> returns = new ArrayList<Object>();
Object retVal = obj.onEvent(returns);

As #Johan said, it is not possible. The only way if you really need it would be for you to store these possible results in a Map mapping the method name to a List or array, or better, use an enum if possible.
Edit:
After reading your comment, I think you should use a HashMap with a Node as the key and a List as value. When you analyse a Node you create the list of exit Nodes in a list, and then map that list to the node.

With use of the command pattern and enum there is a workaround.
public class OnEvent implements Command<EventInfo> {
#Override
public EventInfo execute() {
// do some checking
return EventInfo.A;
}
#Override
public EventInfo[] getValues() {
return EventInfo.values();
}
public static void main(String[] args) {
OnEvent e = new OnEvent();
EventInfo retVal = e.execute();
EventInfo[] values = Utils.getReturnStatements(e);
}
}
enum EventInfo {
A, B, C;
}
interface Command<TYPE extends Enum<?>> extends KnownReturnValues<TYPE> { public TYPE execute(); }
interface KnownReturnValues<TYPE> { public TYPE[] getValues(); }
class Utils {
private Utils() {}
public static <TYPE extends Enum<?>> TYPE[] getReturnStatements(Command<TYPE> c) {
return c.getValues();
}
}

Its not really good programming practice, but you can create a class with 3 public data members, and have your code look something like this. (Ill call the class "myclass")
public a, b, c = null;
//And then your main class would look something like this
if (condition){
myclass.a=whatever;
}
else if (condition){
myclass.b=whatever;
}
else if (condition){
myclass.c=whatever
}
Then you would need another control structure that said something along the lines of
if (myclass.datamember!=null) to make sure you have values in the class data members. Again, this is not good programming practice, but it will work for what you want.

Related

Create a Class That extends Java.util.ArrayList

I am trying to create class that extends the java.util.ArrayList by overriding
the add method in the following way: it does nothing if the object to be added already exists
in the collection; otherwise it calls the add method in the super class to add the object into
the collection.
My code look like that so far but it gives a NullPointerException:
import java.util.ArrayList;
public class myArrayList<E> extends ArrayList<E> {
public ArrayList<E> mylist;
#Override
public boolean add(E e) {
if (!mylist.contains(e)) {
super.add(e);
return true;
} else {
return false;
}
}
}
public static void main(String[] args) {
myArrayList<Integer> listing = new myArrayList<Integer>();
listing.add(4);
listing.add(4);
for (int i = 0; i < listing.size(); i++) {
System.out.println(listing.get(i));
}
}
While we can't be sure this is your problem (unless you show us the stacktrace!), it looks like an NPE is likely to occur in this line:
if (!mylist.contains(e)) {
because mylist is never initialized.
In fact, if you are trying to extend ArrayList rather than create a list wrapper, the mylist variable should not exist at all. The list state is in the superclasses private variables. Instead, the add method should probably be written like this:
#Override
public boolean add(E e) {
if (!super.contains(e)) {
return super.add(e); // See note
} else {
return false;
}
}
Note: in general, you should return whatever the superclass returns here. However, when the superclass is ArrayList, we know1 that add will return true, so this is only "saving" a line of code. There might be marginal performance difference, depending on how smart the JIT optimizer is.
1 - We know because the ArrayList.add javadoc specifically states that true is returned.
But this looks like you are trying to create a "set-like" list class. There could be better alternatives; e.g. LinkedHashSet has a defined iteration order, and addition is O(1) rather than O(N). (Admittedly, LinkedHashSet uses a lot more memory, and it has no efficient equivalent to the positional List.get(int) method.)
You got a NullPointerException on this line if (!mylist.contains(e)) { because myList is not instanciated in the default constructor.
public MyArrayList() {
this.myList = new ArrayList<>();
}
But.. you mix inheritance and composition here...
That means add will be applied to myList and get(index) will be applied on this.. So you actually maintain 2 lists here..
In you example myList.contains will always return false because you never add something into. this -> super.add(e) is the same than this.add(e) and it is a different instance of list.
So just removed myList instance field and replace your add like this :
#Override
public boolean add(E e) {
if (!contains(e)) {
add(e);
return true;
} else {
return false;
}
}
Watch out that this class is not thread-safe. Here there is a check-then-act race condition (check = contains(), act = add())
Finally List are designed to allow duplicates... if you don't want duplicates.. just use a Set

Avoiding ambiguous methods caused by extends/implements

I have a convenience function which takes various types of objects and converts them in a serializable sort of way. For example, JSON-like objects are converted into JSON:
public static <T> String process( List<T> list ) {
if( list instanceof JSONArray ) {
return ((JSONArray) list).toJSONString( );
}
// stringify the list
}
public static String process( JSONAware object ) { // array, map, value, ...
return object.toJSONString( );
}
I'm using the org.json.simple library, so JSONArray extends ArrayList implements JSONAware. But that means that when I send a JSONArray, I get:
reference to process is ambiguous
I'm aware that it could equally go to either method, which is why I have equivalent implementations in both.
Clearly I could replace both functions with one which takes arbitrary Object types, but that would remove a lot of compile-time checking which I'm not happy about. I could also rename one of the functions to force a particular choice, but that complicates the API.
Is there some way I can force a particular choice, or make it obvious to the compiler that it doesn't matter which method gets called in these cases?
You can add
public static void process(JSONArray array) {
process((JSONAware) array);
}
while it is not a general solution, it would solve it in this case.
In this example
public class Example {
static class A {
}
interface B {
}
static class C extends A implements B {
}
static void process(A a) {
}
static void process(B b ) {
}
static void process(C c) {
System.out.println("process C called");
}
public static void main(String... ignored) {
process(new C());
}
prints
process C called

Java Generics -> Function return type

I have a situation like this:
I have a class which looks like:
public class TestClass<T> {
// class body here...
}
And I have a method that looks like this:
public class AnotherTestClass<K> {
private TestClass<K> testClass;
public AnotherTestClass(TestClass<K> testClass) {
this.testClass = testClass;
}
public K testMethod() {
//call methods on param object and pass a value of the same type as testClass.
K returnVal = this.testClass.doSomething();
return returnVal;
}
}
Now I have a factory method which returns an object of type TestClass<?>
public TestClass<?> sampleFactory(int i) {
if( i==1 )
return new TestClass<Integer>();
if( i==2 )
return new TestClass<Double>();
if( i==3 )
return new TestClass<String>();
}
But I cant use that method to pass parameter to my testMethod. Whats the solution for this?
Currently I am writing if else chain blocks to get correct instance. I know its not correct as its impractical to write if else blocks when there are multiple parameters like the one above.
Please suggest an elegant way for this.
EDIT: Sample usage:
package my;
import java.util.ArrayList;
import java.util.List;
public class GenericsSpike {
public static void main( String[] args ) {
TestClass1< ? > tc1 = new TestClass1<Integer>( 123 );
TestClass2< ? > tc2 = new TestClass2<Integer>( 123 );
AnotherTestClass< ? > atc = new AnotherTestClass<Integer>( tc1, tc2 );
atc.testMethod();
}
}
class TestClass1<T> {
private T value;
TestClass1( T val ) {
value = val;
}
// class body here...
public T getValue() {
return value;
}
}
class TestClass2<T> {
private T value;
TestClass2( T val ) {
value = val;
}
// class body here...
public T getValue() {
return value;
}
}
class AnotherTestClass<K> {
public TestClass1<K> testClass1, testClass2;
public AnotherTestClass( TestClass1<K> testClass, TestClass2<K> testClass2 ) {
this.testClass1 = testClass;
}
public K testMethod() {
//Any logic can come here.
System.out.println( testClass1.getValue() );
System.out.println( testClass2.getValue() );
return testClass1.getValue();
}
}
In this case, if tc1 and tc2 are coming from a factory which creates these objects, I want to know whats the decent way to create instance of AnotherClass
Your problem is with this method:
public TestClass<?> sampleFactory(int i) {
The ? wildcard type means "some type, but I don't know what". So you can get a value of type TestClass<?>, but it's not useful to you, because you can't meaningfully interact with the type ? -- you can't create values of type ? (except for null) and you can't call methods on type ? (except methods of java.lang.Object).
What you really want is something like:
public <T> TestClass<T> sampleFactory(TypeToken<T> typeToken) {
That is, if you want your factory to give you back values parameterized by different types, you need to give it something that tells it what type you want. Unfortunately, int isn't enough -- you may know that i==1 means the type will be Integer, but the compiler doesn't know that.
Your description of your problem is a bit too vague for me to understand what you're really trying to achieve, but my guess is that what you really need is either something like super type tokens or maybe something like Guava's ClassToInstanceMap.
One possible solution is to use raw AnotherTestClass type
public class A {
public static void main(String[] args) {
TestClass<?> tc = new TestClass<Integer>();
AnotherTestClass atc = new AnotherTestClass();
atc.testMethod(tc);
}
}
class TestClass<T> {
// class body here...
}
class AnotherTestClass<K> {
public void testMethod(TestClass<K> param) {
}
}
compiles fine. But it's not good idea to use raw types in general case
Java Doc says:
The type of a constructor, instance method, or non-static field M of a raw type C that is not
inherited from its superclasses or superinterfaces is the erasure of its type in the generic
declaration corresponding to C. The type of a static member of a raw type C is the same as its
type in the generic declaration corresponding to C.
Type erasure comes into picture even though the method's type signature doesn't use any type parameters of the class itself,
This is what your method becomes,
public method testMethod(TestClass param) {
}
Your factory method which returns an object of type TestClass<?>, cannot be accomodated in above method.
Using this one you'll be able to pass parameter to your testMethod:
package stackoverflow;
public class Func {
static class TestClass<T> {
}
static class AnotherTestClass {
public <K> TestClass<K> testMethod(TestClass<K> param) {
return param;
}
}
static class Factory {
public static <E> TestClass<E> sampleFactory(int i) {
if (i == 1)
return (TestClass<E>) new TestClass<Integer>();
if (i == 2)
return (TestClass<E>) new TestClass<Double>();
if (i == 3)
return (TestClass<E>) new TestClass<String>();
throw new IllegalArgumentException();
}
}
public static void main(String[] args) {
new AnotherTestClass().testMethod(Factory.sampleFactory(1));
}
}

Using a Set with one Class but find with a String

I have a Java Set<MyClass> on which I've overridden equals and hashCode to use the String name; variable.
public class MyClass{
final String name;
public boolean equals(Object o){...}
public int hashCode(){return name.hashCode();}
}
Is there anyway I can get my Object out of the HashSet using something like
MyClass o = set.get("nameofmyobject");
Is there a way to do this in Java, or a datastructure? or do I need to change up all of my Sets to Maps?
No. You need to change to a Map. None of the methods of Set return an element.
Addendum A
If you don't care about speed you can always search manually:
MyClass find(String name, Set<MyClass> set)
{
MyClass wrapper = new MyClass(name);
for (MyClass e : set) {
if (wrapper.equals(e)) {
return e;
}
}
return null;
}
Addendum B
If you use a TreeSet you can use floor:
MyClass find(String name, TreeSet<MyClass> set)
{
MyClass wrapper = new MyClass(name);
MyClass candidate = set.floor(wrapper);
if (candidate != null && wrapper.equals(candidate)) {
return candidate;
} else {
return null;
}
}
Have a look at this question. The answer is no. Sets are not for getting elements, but to look for equality. Use a Map or List insteed.
As Tim said you can't. And if so you would have to call it like set.get(myClassInstance); and not set.get(some member of the stored instance)
Use
Map<String, MyClass> myMap = new HashMap<String, MyClass>();

how to check the Class Type(instanceof) in java template method?

public class Test {
private static Object createInstance(String classPath) {
try {
Class<?> tClass = Class.forName(classPath);
if (tClass != null) {
return tClass.newInstance();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#SuppressWarnings("unchecked")
public final static <INPUT, OUTPUT> Filter<INPUT, OUTPUT> getFilter(String path) {
return (Filter<INPUT, OUTPUT>) createInstance(path);
}
public final static <INPUT, OUTPUT> OUTPUT filter(String path, INPUT mes) {
Filter<INPUT, OUTPUT> filter = getFilter(path);
//How to check the INPUT and OUTPUT type here?
//if(INPUT instanceof String){ ... } not work
return filter.filter(mes);
}
}
refer to my earlier question here
thanks for help :)
Other answer are certainly correct. Anyway i think you are doing something quite unusual.
I'll try to explain:
Generics are use for static polymorphism. An instance of a generic type is determined at compile time.
Constructs like instanceof are used to check dynamic type of an object at runtime, so if you are using them, you can simply avoid the use of generics.
(You can use a generic Object as parameter for your function and then use instanceof to check its type)
For example:
public void method(Object o){
if (o instanceof String){} //do what you want
else ....
}
Typically, if you use generics, you are just trying to avoid that constructs. Typically a generic type can implements a well know interface, in a way that any operation performed upon that object into your filter method, could be performed for different types of objects implementing that interface and without knowing the specific type of objects involved.
I don't know exactly what are the polymorphic feature that you need, anyway you could try also something like that:
public interface polymorphicObj{
public method();
}
public class Filter<GENERIC implements polymorphicObj>{
public filter(GENERIC obj){
obj.method(); //you don't need to know of which specific type is polymorphicObj
}
}
if mes instanceof String should work.
Instead of checking INPUT, how about checking the actual parameter?
if(mes instanceof String) {
You will need instance of INPUT:
class A<INPUT>{
void typeOf(INPUT input){
if(input.getClass() == "".getClass()){
System.out.println("Input is String");
}
}
}
all objects extends Object co they have getClass method. You could use it to check class.

Categories