I would like to call method(using reflection) which has parameter Interface - i.e: List but with implementation of List.
For example:
public class Test {
public static void main(String[] args) throws NoSuchMethodException {
Method method = Test1.class.getMethod("method", new Class[]{ArrayList.class});
}
public class Test1 {
public void method(List list) {
System.out.println("method");
}
}
}
I get NoSuchMethodException. In this case i know which params i get, problem is that I want to use this in general when i don't "statically" know param types.
Is possible that getMethod returns also method which has interface as parameter? Or i have to write my own "methodsearcher"
Thank you.
EDIT:
It's much more complicated. I'm trying to write something like "dynamic modular architecture" in my program. I have Core, which should comunicate with other modules. So i don't know params classes in programming time but in runtime.
public Object processMessage(String target, String methodName, List<Object> params, Object returnNonExist) {
Module m = modules.get(target);
if (m == null) {
return returnNonExist;
} else {
Class[] paramsTypes = new Class[params.size()];
for (int i = 0; i < params.size(); i++) {
paramsTypes[i] = params.get(i).getClass();
}
}
try {
Method method = m.getClass().getMethod(methodName, paramsTypes);
Object result = method.invoke(m, params.toArray());
return result;
}
Is it better?
I probably found solution - I have to write my own "method searcher" which respect interface implementation and superclases. It looks like this:
public static Method findMethod(Object m, String methodName, Class[] paramsTypes) {
Method[] metody = m.getClass().getDeclaredMethods();
List<Method> sameNames = new ArrayList<Method>();
// filter other names
for (Method meth : metody) {
if (meth.getName().equals(methodName)) {
sameNames.add(meth);
}
}
// lets find best candidate
if (sameNames.isEmpty()) {
return null;
} else {
// filter other count of parameters
List<Method> sameCountOfParameters = new ArrayList<Method>();
for (Method meth : sameNames) {
if (meth.getParameterTypes().length == paramsTypes.length) {
sameCountOfParameters.add(meth);
}
}
if (sameCountOfParameters.isEmpty()) {
return null;
} else {
for (Method meth : sameCountOfParameters) {
// first one, which is suitable is the best
Class<?>[] params = meth.getParameterTypes();
boolean good = true;
for (int i = 0; i < params.length && good; i++) {
if (params[i].isInterface() && Arrays.asList(paramsTypes[i].getInterfaces()).contains(params[i])) {
//if i-th paramater type is Interface and we search method with its implementation
good = true;
continue;
} else {
// if we call it with subclass and parameter typ is superclass
if (paramsTypes[i].getSuperclass().equals(params[i])) {
good = true;
continue;
}
}
good = false;
}
if (good) {
return meth;
}
}
}
}
return null;
}
I'am using this after standard getMethod throws "NoSuchMethodException" (It is in about 5% cases, so i don't care about speed.
You should use List class, not ArrayList.
Method method = Test1.class.getMethod("method", new Class[]{List.class});
Great answer from #radeczek. I extended it to work on subclasses ...
public Method findMethod(String name, Class<?>[] paramsTypes) {
Method[] methods = object.getClass().getMethods();
List<Method> sameNames = new ArrayList<Method>();
// filter other names
for (Method m : methods) {
if (m.getName().equals(name)) {
sameNames.add(m);
}
}
// lets find best candidate
if (sameNames.isEmpty()) {
return null;
} else {
// filter other count of parameters
List<Method> sameCountOfParameters = new ArrayList<Method>();
for (Method m : sameNames) {
if (m.getParameterTypes().length == paramsTypes.length) {
sameCountOfParameters.add(m);
}
}
if (sameCountOfParameters.isEmpty()) {
return null;
} else {
for (Method m : sameCountOfParameters) {
// first one, which is suitable is the best
Class<?>[] params = m.getParameterTypes();
boolean good = true;
for (int i = 0; i < params.length && good; i++) {
// Recurse into subclasses
good = findSubclass(paramsTypes[i],params[i]);
}
if (good) {
return m;
}
}
}
}
return null;
}
/**
* Recursive check for interfaces of superclasses.
*
* #param paramType
* #param param
* #return
*/
private boolean findSubclass(Class<?> paramType, Class<?> param) {
if (param.isInterface() && Arrays.asList(paramType.getInterfaces()).contains(param)) {
return true;
} else {
if (paramType.getSuperclass() != null) {
return findSubclass(paramType.getSuperclass(), param);
} else {
return false;
}
}
}
Related
I have a number of methods, each of which checks the same set of conditions and returns a null value if none of the conditions are met, otherwise returns an object of different classes.
Is there a way to not have to write all of these terms for each function and use less code?
public A methode1()
{
if ///something
return A("xxx")
else if ///something
return A("yyy")
else if ///something
return A("zzzz")
else
return Error() // or return null
}
public B methode2()
{
if ///something
return B("mmmm")
else if ///something
return B("nnn")
else if ///something
return B("bbbb")
else
return Error() // or return null
}
public C methode3()
{
if ///something
return C("oooo")
else if ///something
return C("ggg")
else if ///something
return C("llll")
else
return Error() // or return null
}
You can combine template method pattern with generics:
public abstract class AbstractTemplate<T>
{
public T methode()
{
if ///something
return Do1();
else if ///something
return Do2();
else if ///something
return Do3();
else
return Error() // or return null
}
protected abstract T Do1();
protected abstract T Do2();
protected abstract T Do3();
}
public class ConcreteATemplate : AbstractTemplate<A>
{
protected override T Do1() => A("xxx");
protected override T Do2() => A("yyy");
protected override T Do3() => A("zzzz");
}
And use it inside your methods:
public A methode1() => new ConcreteATemplate().methode(); // also can "cache" instance in your case in static readonly field.
Standard approch is , you can use a factory class with interface/abstract class
public interface IOutput {
}
public class Output1 : IOutput{
}
public class Output2 : IOutput{
}
public class MyFactory
{
public IOutput Get()// add args list of any
{
if(condition) // you can use args in condition if necessary
return new Output1();
else
return new Output2();
}
}
You can use generic method and repository pattern. Here is a generic method example with C#. I think it may give you some idea..
public static async Task<List<ObjectType>> GetDataList<ObjectType>(UserAuthorization token) where ObjectType : BaseModel
{
List<ObjectType> data = new List<ObjectType>();
try
{
if(token.UserTypes.Count > 0)
{
Type genericClass = typeof(Repository<>);
Type constructedClass = genericClass.MakeGenericType(typeof(ObjectType));
MERPDbContext mERPContext = new MERPDbContext();
var created = (Repository<ObjectType>)Activator.CreateInstance(constructedClass, mERPContext);
if (token.UserTypes[0].Id == (byte)UserTypes.SuperAdmin)
{
var sub = await created.GetAsync();
data = sub.ToList();
}
else if (token.UserTypes[0].Id == (byte)UserTypes.InstituteAdmin)
{
data = await created.FilterListAsync
(x => x.InstituteId == token.InstituteID);
}
else
{
data = await created.FilterListAsync(x =>
x.InstituteId == token.InstituteID && x.CampusId == token.CampusID);
}
}
}
catch (Exception e)
{
}
return data;
}
You could use a method with a generic type parameter and a set of initial values.
private T GetIfOkay<T>(string a, string b, string c)
where T : new()
{
if (something)
return new T(a);
else if (something else)
return new T(b);
else if (yet something else)
return new T(c);
else
return null;
}
public A methode1()
{
return GetIfOkay<A>("xxx", "yyy", "zzzz");
}
public B methode2()
{
return GetIfOkay<B>("mmmm", "nnn", "bbbb");
}
// etc.
If you need a more dynamic behaviour, #donggas90's solution.
See:
Generic Methods (C# Programming Guide)
C# Generics (TutorialsTeacher)
According to your comment, I tried to rewrite your sample, hope this will help you. ask freely if you need more clarity.
class Program
{
static void Main(string[] args)
{
var objFactory = new MyFactory();
// Get and cast return object
A a1= (A) objFactory.ConsolidatedMethod("Condition 1 for Objct A", "xxx");
// Or Directly assian to base object
IOutput a2 = objFactory.ConsolidatedMethod("Condition 2 for Objct A", "yyyy");
// use anonymous object
var b1= objFactory.ConsolidatedMethod("Condition 1 for Objct B", "mmmm");
var nullcheck1 = objFactory.ConsolidatedMethod("null conditionj", "i'm null");
}
}
interface IOutput
{
}
class A : IOutput
{
public A(string objParam)
{
}
}
class B : IOutput
{
public B(string objParam)
{
}
}
class NullOutput : IOutput
{
public NullOutput(string objParam)
{
}
}
class MyFactory
{
/// <summary>
/// Demo
/// </summary>
/// <param name="arg">you can use this based on your requirement </param>
/// <param name="objparam">you can use this based on your requirement </param>
/// <returns>IOutput</returns>
public IOutput ConsolidatedMethod(string arg, string objparam)
{
IOutput _output=default;
if (arg == "Condition 1 for Objct A")
_output = new A(objparam);
else if (arg == "Condition 2 for Objct A")
_output = new A(objparam);
else if (arg == "Condition 1 for Objct b")
_output = new B(objparam);
else if (arg == "Condition 2 for Objct B")
_output = new B(objparam);
else
_output = new NullOutput(objparam);
return _output;
}
}
I am trying to create a base abstract class for unit testing. It is very easy to do this in C# but couldn't in java. My idea is that I will have a TestFor class which is to be used as base for unit test. T represents the type under test. In this class I want to create the The object of type T with all its parameters of longest constructor MOCKED. That mean I have to reflect the class, get the longest constructor, pull out the parameters, create mock of this parameter and then create the object of type T. I have the following code but not working. Anyone who can try
public abstract class TestFor<T> {
protected Class<T> _class = null;
public HashMap<Class, Class<?>> _mocks = new HashMap<Class, Class<?>>();
protected T Target = null;
protected TestFor(Class<T> cls) {
_class = cls;
Constructor<T>[] allConstructors = (Constructor<T>[]) _class.getDeclaredConstructors();
Constructor<T> ctorWithLongestParameter = null;
int max = 0;
for (Constructor ctor : allConstructors) {
if (ctor.getParameterTypes().length > max) {
ctorWithLongestParameter = ctor;
max = ctor.getParameterTypes().length;
}
}
final List<Object> objects = new ArrayList<Object>();
int i = 0;
for (Class<?> p : ctorWithLongestParameter.getParameterTypes()) {
Class<?> mock = Mockito.mock(p.getClass()); //This does not work
_mocks.put(p.getClass(), mock);
objects.add(mock);
}
try {
Target = (T) ctorWithLongestParameter.newInstance(objects);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
public <E> E the(Class clss) {
return (E) _mocks.get(clss);
}
}
There is a several bugs in your code - logic, types, generics... Try this instead:
public abstract class TestFor<T> {
protected Class<T> _class = null;
public Map<Class, Object> _mocks = new HashMap<>();
protected T Target = null;
protected TestFor(Class<T> cls) {
_class = cls;
List<Constructor> allConstructors = Arrays.asList(_class.getDeclaredConstructors());
Constructor ctorWithLongestParameter = Collections.max(allConstructors,
(o1, o2) -> Integer.compare(o1.getParameterCount(), o2.getParameterCount()));
List<Object> objects = new ArrayList<>();
int i = 0;
for (Class<?> type : ctorWithLongestParameter.getParameterTypes()) {
Object mock = _mocks.get(type);
if (mock == null) {
mock = Mockito.mock(type);
_mocks.put(type, mock);
}
objects.add(mock);
}
try {
Target = _class.cast(ctorWithLongestParameter.newInstance(objects.toArray(new Object[objects.size()])));
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
public <E> E the(Class<E> cls) {
return cls.cast(_mocks.get(cls));
}
public static void main(String[] args) {
TestFor<A> test = new TestFor<A>(A.class) {};
System.out.println(test.Target);
System.out.println(test.the(Object.class));
System.out.println(test.the(Number.class));
}
public static class A {
public A() {
System.out.println("Empty constructor");
}
public A(Object o) {
System.out.println("Constructor [o=" + o + ']');
}
public A(Object o, Number n) {
System.out.println("Constructor [o=" + o + ", n=" + n + ']');
}
}
}
This code works with Java 8, however after small modifications it will work on the elder versions.
The following chunks of code define how the compiler for my custom JVM programming language resolves missing abstract methods and links methods to their supertype methods. The inheritance model is like in Java 8, you can have both abstract and concrete (default) methods in interfaces and abstract classes and concrete methods only in non-abstract classes. Multiple inheritance is obviously only allowed for interfaces:
CodeClass.java:
public class CodeClass extends AbstractClass
{
// ...
public void checkTypes(MarkerList markers, IContext context)
{
// ...
if (this.superType != null)
{
this.superType.getTheClass().checkMethods(markers, this, this.superType);
}
for (int i = 0; i < this.interfaceCount; i++)
{
IType type = this.interfaces[i];
type.getTheClass().checkMethods(markers, this, type);
}
}
// ...
}
AbstractClass.java:
public class AbstractClass
{
protected ClassBody body;
// ...
public boolean checkImplements(MarkerList markers, IClass iclass, IMethod candidate, ITypeContext typeContext)
{
if (candidate.getTheClass() == this)
{
return !candidate.hasModifier(Modifiers.ABSTRACT);
}
if (this.body != null && this.body.checkImplements(markers, iclass, candidate, typeContext))
{
return true;
}
if (this.superType != null)
{
if (this.superType.getTheClass().checkImplements(markers, iclass, candidate, this.superType.getConcreteType(typeContext)))
{
return true;
}
}
for (int i = 0; i < this.interfaceCount; i++)
{
IType type = this.interfaces[i];
if (type.getTheClass().checkImplements(markers, iclass, candidate, type.getConcreteType(typeContext)))
{
return true;
}
}
return false;
}
public void checkMethods(MarkerList markers, IClass iclass, ITypeContext typeContext)
{
if (this.body != null)
{
this.body.checkMethods(markers, iclass, typeContext);
}
if (this.superType != null)
{
this.superType.getTheClass().checkMethods(markers, iclass, this.superType.getConcreteType(typeContext));
}
for (int i = 0; i < this.interfaceCount; i++)
{
IType type = this.interfaces[i];
type.getTheClass().checkMethods(markers, iclass, type.getConcreteType(typeContext));
}
}
// ...
}
ClassBody.java:
public class ClassBody
{
// ...
public boolean checkImplements(MarkerList markers, IClass iclass, IMethod candidate, ITypeContext typeContext)
{
for (int i = 0; i < this.methodCount; i++)
{
if (this.methods[i].checkOverride(markers, iclass, candidate, typeContext))
{
return true;
}
}
return false;
}
public void checkMethods(MarkerList markers, IClass iclass, ITypeContext typeContext)
{
for (int i = 0; i < this.methodCount; i++)
{
IMethod candidate = this.methods[i];
if (iclass.checkImplements(markers, iclass, candidate, typeContext))
{
continue;
}
if (candidate.hasModifier(Modifiers.ABSTRACT) && !iclass.hasModifier(Modifiers.ABSTRACT))
{
markers.add(iclass.getPosition(), "class.method.abstract", iclass.getName(), candidate.getName(), this.theClass.getName());
}
}
}
// ...
}
method.checkOverride simply checks if the signature of the candidate and the receiver match, and if the iclass parameter and the container class of the method are the same type, the candidate gets added to the list of overriden methods.
This code is all nice and pretty, and also works how I intended it to work, but I fear that it will blow up for a deep class hierarchy with lots of methods (like a collection framework), because the entire process is a strongly recursive operation that requires checking lots and lots of types and iterating through arrays of methods over and over again. Is there a less complex and more performant solution for large class trees, and how do other compilers (e.g. javac or scalac) solve this problem?
I want to have something like this below (example how I would do this in C#), to get typed value from SQLiteDB:
private T GetValueFromDB<T>(String colName) {
object returnValue = null;
switch (typeof(T)) {
case Boolean:
returnValue = dbData.getInt(colName) == 1;
break;
case Int32:
returnValue = dbData.getInt(colName);
break;
case Int64:
returnValue = dbData.getLong(colName);
break;
case String:
returnValue = dbData.getString(colName);
break;
}
return (T)returnValue;
}
Is there a possibility (with switch case or if else) to implement it in Java?
If you already know the type when calling the method, you could do something like this:
private T GetValueFromDB<T>(String colName, Class<T> returnType) {
if(returnType.equals(Boolean.class)) {
return (T)(dbData.getInt(colName) == 1);
} else if(returnType.equals(Int32.class)) {
// and so on
}
}
Java uses type erasure so it is impossible to determine type of T at runtime.
I have made inteface switch, maybe it can be useful for someone :
new ISwitch(pagerCtrl.getPager().getFragmentByID(fragment_id))
.addCase(new ISwitch.CaseListener<Type1>() {
#Override
public void Case(Type1 instance) {
}
}).addCase(new ISwitch.CaseListener<Type2>() {
#Override
public void Case(Type2 instance) {
}
}).addDefault(new ISwitch.DefaultListener() {
#Override
public void Default() {
}
}).build();
public class ISwitch {
public interface CaseListener<T> {
void Case(T instance);
}
public interface DefaultListener {
void Default();
}
Object value;
LinkedList<CaseListener<?>> col = new LinkedList<>();
DefaultListener defaultListener;
public ISwitch(Object value) {
this.value = value;
}
public void build() {
boolean wasNotifiedMinimumOnce = false;
for (CaseListener<?> c : col) {
try {
CaseListener<Object> l = (CaseListener<Object>) c;
l.Case(value);
wasNotifiedMinimumOnce = true;
break;
} catch (ClassCastException e) {
}
}
if ( !wasNotifiedMinimumOnce ) {
if ( defaultListener != null ) {
defaultListener.Default();
}
}
}
public ISwitch addCase(CaseListener<?> caseListener) {
col.add(caseListener);
return this;
}
public ISwitch addDefault(DefaultListener defaultListener) {
this.defaultListener = defaultListener;
return this;
}
}
The small drawback of implementation is that we cant make check instanceof, that why i catch it on cast. For me its not big deal, but it can be performance issue on java server code executed XXXXXX times each seconds.
I have two objects of same type.
Class A {
String a;
List b;
int c;
}
A obj1 = new A();
A obj2 = new A();
obj1 => {a = "hello"; b = null; c = 10}
obj2 => {a = null; b = new ArrayList(); c = default value}
Can you please let me know what is the best way to combine this objects into single object?
obj3 = {a = "hello"; b = (same arraylist from obj2); c = 10}
This works as long as you have POJOs with their own getters and setters. The method updates obj with non-null values from update. It calls setParameter() on obj with the return value of getParameter() on update:
public void merge(Object obj, Object update){
if(!obj.getClass().isAssignableFrom(update.getClass())){
return;
}
Method[] methods = obj.getClass().getMethods();
for(Method fromMethod: methods){
if(fromMethod.getDeclaringClass().equals(obj.getClass())
&& fromMethod.getName().startsWith("get")){
String fromName = fromMethod.getName();
String toName = fromName.replace("get", "set");
try {
Method toMetod = obj.getClass().getMethod(toName, fromMethod.getReturnType());
Object value = fromMethod.invoke(update, (Object[])null);
if(value != null){
toMetod.invoke(obj, value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
I am using Spring Framework. I was facing the same issue on a project.
To solve it i used the class BeanUtils and the above method,
public static void copyProperties(Object source, Object target)
This is an example,
public class Model1 {
private String propertyA;
private String propertyB;
public Model1() {
this.propertyA = "";
this.propertyB = "";
}
public String getPropertyA() {
return this.propertyA;
}
public void setPropertyA(String propertyA) {
this.propertyA = propertyA;
}
public String getPropertyB() {
return this.propertyB;
}
public void setPropertyB(String propertyB) {
this.propertyB = propertyB;
}
}
public class Model2 {
private String propertyA;
public Model2() {
this.propertyA = "";
}
public String getPropertyA() {
return this.propertyA;
}
public void setPropertyA(String propertyA) {
this.propertyA = propertyA;
}
}
public class JustATest {
public void makeATest() {
// Initalize one model per class.
Model1 model1 = new Model1();
model1.setPropertyA("1a");
model1.setPropertyB("1b");
Model2 model2 = new Model2();
model2.setPropertyA("2a");
// Merge properties using BeanUtils class.
BeanUtils.copyProperties(model2, model1);
// The output.
System.out.println("Model1.propertyA:" + model1.getPropertyA(); //=> 2a
System.out.println("Model1.propertyB:" + model1.getPropertyB(); //=> 1b
}
}
Maybe something like
class A {
String a;
List<..> b;
int c;
public void merge(A other) {
this.a = other.a == null ? this.a : other.a;
this.b.addAll(other.b);
this.c = other.c == 0 ? this.c : other.c;
}
}
A a1 = new A();
A a2 = new A();
a1.a = "a prop";
a2.c = 34;
a1.merge(a2);
A.merge might return a new A object instead of modifing current.
Just accommodating boolean sync. and case sensitive(camel notation)
public boolean merge(Object obj){
if(this.equals(obj)){
return false;
}
if(!obj.getClass().isAssignableFrom(this.getClass())){
return false;
}
Method[] methods = obj.getClass().getMethods();
for(Method fromMethod: methods){
if(fromMethod.getDeclaringClass().equals(obj.getClass())
&& (fromMethod.getName().matches("^get[A-Z].*$")||fromMethod.getName().matches("^is[A-Z].*$"))){
String fromName = fromMethod.getName();
String toName ;
if(fromName.matches("^get[A-Z].*")){
toName = fromName.replace("get", "set");
}else{
toName = fromName.replace("is", "set");
}
try {
Method toMetod = obj.getClass().getMethod(toName, fromMethod.getReturnType());
Object value = fromMethod.invoke(this, (Object[])null);
if(value != null){
toMetod.invoke(obj, value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
return true;
}
If you create getters and setters for the attributes, you can use the copyProperties method from Commons BeanUtils.
Add this method to your POJO, then use it like myObject.merge(newObject). It uses generics to loop through your POJO's fields, so you don't mention any field names:
/**
* Fill current object fields with new object values, ignoring new NULLs. Old values are overwritten.
*
* #param newObject Same type object with new values.
*/
public void merge(Object newObject) {
assert this.getClass().getName().equals(newObject.getClass().getName());
for (Field field : this.getClass().getDeclaredFields()) {
for (Field newField : newObject.getClass().getDeclaredFields()) {
if (field.getName().equals(newField.getName())) {
try {
field.set(
this,
newField.get(newObject) == null
? field.get(this)
: newField.get(newObject));
} catch (IllegalAccessException ignore) {
// Field update exception on final modifier and other cases.
}
}
}
}
}
There is a dynamic solution to merge any two objects which require Reflection and Recursion.
public <T> T merge(T local, T remote, ArrayList<String> listOfClass)
throws IllegalAccessException, InstantiationException {
Class<?> clazz = local.getClass();
Object merged = clazz.newInstance();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
Object localValue = field.get(local);
Object remoteValue = field.get(remote);
if (localValue != null) {
if (listOfClass.contains(localValue.getClass().getSimpleName())) {
field.set(merged, this.merge(localValue, remoteValue, listOfClass));
} else {
field.set(merged, (remoteValue != null) ? remoteValue : localValue);
}
} else if (remoteValue != null) {
field.set(merged, remoteValue);
}
}
return (T) merged;
}
Variable Description:
local: The object on to which the other will be merged
remote: The object which will be merged to the local object
listOfClass: The ArrayList of custom classes in the given object
The function returns a merged object which is good to go.
Kudos! :)
In your very special case it looks like you want a new object that takes the real values from both instances. Here is an implementation that will do that. The method should be add to class A so that it can access the fields.
public A specialMergeWith(A other) {
A result = new A();
result.a = (a == null ? other.a : a);
result.b = (b == null ? other.b : b);
result.c = (c == DEFAULT_VALUE ? other.c : c);
return result;
}
public static Object mergeObjects(Object source, Object target) throws Exception {
Field[] allFields = source.getClass().getDeclaredFields();
for (Field field : allFields) {
if(Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers())){
continue;
}
if (!field.isAccessible() && Modifier.isPrivate(field.getModifiers()))
field.setAccessible(true);
if (field.get(source) != null) {
field.set(target, field.get(source));
}
}
return target;
}
Using java reflection, support only for the same class.