Java reflection error Java.lang.NoSuchMethodException, but method exists - java

I can't get to work java reflection in Spring boot with Controller and JdbcTemplate.
Default controller looks like:
public class DefaultController {
private static final Logger logger = LoggerFactory.getLogger(DefaultController.class);
public JsonResponseDataModel selectOneAuto(Long id, Class<?> repository, HttpServletResponse response){
final JsonResponseDataModel result = new JsonResponseDataModel();
System.out.println("The name of class is " + repository.getName());
Method[] methods = repository.getMethods();
for (Method method : methods) {
System.out.println("Method: " + method.getName());
}
try {
//Method method = repository.getClass().getMethod("selectOne", Long.class);
Method method = repository.getClass().getDeclaredMethod("selectOne", Long.class);
method.invoke(repository, id);
logger.info("selectOneAuto : id={} ", id);
} catch (EmptyResultDataAccessException e) {
result.setEmptyResultDataAccessException("id", id.toString());
} catch (DataAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return result;
}
}
Inside CompanyRepository class is defined selectOne method with Long input:
#Transactional(readOnly=true)
public CompanyModel selectOne(Long id) {
CompanyModel result = null;
final String sql = "SELECT * FROM company WHERE id=?";
return jdbcTemplate.queryForObject(sql, new Object[]{id}, new CompanyRowMapper());
}
When I create a new class "CompanyController extends DefaultController" and call method selectOneAuto:
selectOneAuto(id, new CompanyRepository().getClass(), response);
Then it ends with error on line "Method method = repository.getClass().getDeclaredMethod("selectOne", Long.class);"
"Java.lang.NoSuchMethodException: java.lang.Class.selectOne(java.lang.Long)"
But the for loop inside "selectOneAuto" method outputs method named "selectOne". What is wrong here?

Your code attempts to call the method on an instance of Class.
method.invoke(repository, id);
repository object is an instance of Class since you are passing new CompanyRepository().getClass() as parameter.
The second point to be noted is repository is an instance of Class already so there is no need to call getClass() on this object.
You should obtain the method object using the following code :
Method method = repository.getDeclaredMethod("selectOne", Long.class);
And then this should work :
CompanyRepository repsitoryObj = new CompanyRepository();
method.invoke(repsitoryObj, id);
Or a better and cleaner way is to simply change the type of your repository parameter as CompanyRepository your method will look as follows:
public JsonResponseDataModel selectOneAuto(Long id, CompanyRepository repository, HttpServletResponse response){
final JsonResponseDataModel result = new JsonResponseDataModel();
System.out.println("The name of class is " + repository.getClass().getName());
Method[] methods = repository.getClass().getMethods();
for (Method method : methods) {
System.out.println("Method: " + method.getName());
}
try {
//Method method = repository.getClass().getMethod("selectOne", Long.class);
Method method = repository.getClass().getDeclaredMethod("selectOne", Long.class);
method.invoke(repository, id);
logger.info("selectOneAuto : id={} ", id);
} catch (EmptyResultDataAccessException e) {
result.setEmptyResultDataAccessException("id", id.toString());
} catch (DataAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return result;
}

Related

Spring: Generic Resource Controller

I want to create a generic controller that would like something like this:
#RequestMapping("/api/v1/resource/{resource}")
public class StandardController {
private StandardResourceService standardResourceService;
public StandardController(StandardResourceService standardResourceService) {
this.standardResourceService = standardResourceService;
}
#GetMapping("/{id}")
public Object getResource(
#PathVariable(value="resource") String resource,
#PathVariable(value="id") Long id,
HttpServletRequest request){
return standardResourceService.getEntity(id, resource);
}
#PostMapping
#Transactional
Object newResource(#PathVariable(value="resource") String resource, #RequestBody Object newObject) {
standardResourceService.postResource(resource, newObject);
return newObject;
}
}
The idea is that I don't want to have a lot of endpoints/services/controllers for each entity I'll define in the project. I want to create a standard one for each entity and if I need some custom behaviour for some entities, I'll just extend the base service/controller.
The service I've made looks like this:
#Service
public class StandardResourceService {
#Autowired
private EntityManager entityManager;
#Autowired
private ModelMapper modelMapper;
public <T, ID> T findById(Class<T> type, ID id) {
return entityManager.find(type, id);
}
#Transactional
public void saveObject(Object object) {
entityManager.persist(object);
}
public Object getEntity(long resourceId, String resource) throws EntityNotFoundException {
Object resourceOpt;
Object dto;
try{
Class<?> cls = Class.forName("com.base.package.models." + resource);
resourceOpt = findById(cls, resourceId);
}catch (ClassNotFoundException ex){
throw new EntityNotFoundException("Resource " + resource + " could not be found with id: " + resourceId);
}
if(resourceOpt == null) {
throw new EntityNotFoundException("Resource " + resource + " could not be found with id: " + resourceId);
}
try {
Class<?> dtoClass = Class.forName("com.base.package.dto." + resource + "DTO");
dto = modelMapper.map(resourceOpt, dtoClass);
} catch (ClassNotFoundException ex) {
return resourceOpt;
}
return dto;
}
public Object postResource(String resource, Object newObject) throws RuntimeException {
try{
Class<?> clazz = Class.forName("com.base.package.models." + resource);
//saveObject(instance);
}catch (ClassNotFoundException ex){
throw new EntityNotFoundException("");
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
return newObject;
}
}
The GET is working pretty good. I return a DTO if any, otherwise I return the entity itself.
By the way when using the POST I don't know how to instantiate the correct class with the body I'm sending in the POST.
Is there a way to do this?
Am I approaching this problem correctly?

Reflection on swing components

I'm trying to assign a value to a swing component through reflection. Let's use a JCheckBox for example. I have the following class:
public class JCheckBoxTest
{
private JCheckBox test;
public JCheckBoxTest()
{
this.test = new JCheckBox();
}
public reflectionTest()
{
Field field;
Method method;
field = this.getClass().getDeclaredField("test");
method = field.getType().getSuperclass().getDeclaredMethod("setSelected");
method.invoke(field, "true");
}
}
This code fails at:
method = field.getType().getSuperclass().getDeclaredMethod("setSelected");
because it cannot find the specified "setSelected" method since it is located inside the inner class "ToggleButtonModel" of the superclass "JToggleButton" which is extended by the "JCheckBox" class.
What would be the best approach to solve this?
Thanks.
Edit: Corrected typo in code.
Class#getMethod and Class#getDeclaredMethod both provide the means to supply the name of the method and optional parameters
JCheckBox#setSelected requires a boolean paramater, so you really should be using
method = field.getClass().getDeclaredMethod("setSelected", boolean.class);
But as you've noted, this is unlikely to work, instead, you could try
method = field.getClass().getMethod("setSelected", boolean.class);
Now, I've also had this fail to work as well, which is why I tend to use something like...
public static Method findMethod(Class parent, String name, Class... parameters) throws NoSuchMethodException {
Method method = null;
try {
method = parent.getDeclaredMethod(name, parameters);
} catch (NoSuchMethodException exp) {
try {
method = parent.getMethod(name, parameters);
} catch (NoSuchMethodException nsm) {
if (parent.getSuperclass() != null) {
method = findMethod(parent.getSuperclass(), name, parameters);
} else {
throw new NoSuchMethodException("Could not find " + name);
}
}
}
return method;
}
which is a little brute force.
So with that in mind...
JCheckBox cb = new JCheckBox();
try {
Method method = cb.getClass().getDeclaredMethod("setSelected", boolean.class);
System.out.println("1. " + method);
} catch (NoSuchMethodException | SecurityException ex) {
ex.printStackTrace();
}
try {
Method method = cb.getClass().getMethod("setSelected", boolean.class);
System.out.println("2. " + method);
} catch (NoSuchMethodException | SecurityException ex) {
ex.printStackTrace();
}
try {
Method method = findMethod(cb.getClass(), "setSelected", boolean.class);
System.out.println("3. " + method);
} catch (NoSuchMethodException ex) {
ex.printStackTrace();
}
Which outputs something like...
java.lang.NoSuchMethodException: javax.swing.JCheckBox.setSelected(boolean)
2. public void javax.swing.AbstractButton.setSelected(boolean)
3. public void javax.swing.AbstractButton.setSelected(boolean)
at java.lang.Class.getDeclaredMethod(Class.java:2130)
at test.Test.main(Test.java:13)
Disclaimer
Reflection like this should be a last resort. It's slow and prone to code refactoring

Count traffic separately for each SIM on 2SIM MTK-based phone

Any app I could find on GPlay counts traffic for both SIM while in Settings-Data Usage traffic is counted for each SIM. I used jd-gui to see how it's done and have found that classes from private API were used.
import android.net.INetworkStatsService;
import android.net.INetworkStatsService.Stub;
import android.net.INetworkStatsSession;
import android.net.NetworkPolicy;
import android.net.NetworkPolicyManager;
import android.net.NetworkStats;
import android.net.NetworkStats.Entry;
import android.net.NetworkStatsHistory;
import android.net.NetworkStatsHistory.Entry;
import android.net.NetworkTemplate;
Can I use reflection to use them?
Update.
I've tried to use Reflection. Executing this code give me an exception "java.lang.InstantiationException: can't instantiate class android.net.INetworkStatsService"
Class<Object> MyINetworkStatsService = null;
try {
MyINetworkStatsService = (Class<Object>) Class.forName("android.net.INetworkStatsService");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Object mStatsService = null;
try {
mStatsService = MyINetworkStatsService != null ? MyINetworkStatsService.newInstance() : null;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
Upd. Because both StatsService and StatsSession are interfaces, I can't instantiate them and should use Proxy. Can anyone help with that?
Upd. I've made an effort
String id = getActiveSubscriberId(mContext);
try {
Object tmpl = null;
long stats = 0;
Class<?> a = Class.forName("android.net.NetworkTemplate");
Class<?> b = Class.forName("android.net.INetworkStatsService");
Method getState = b.getMethod("getNetworkTotalBytes", a, long.class, long.class);
Method[] am = a.getDeclaredMethods();
Method getTemplate = null;
for (Method m : am) {
if (m.getName().equalsIgnoreCase("buildTemplateMobileAll")) {
getTemplate = m;
break;
}
}
if (getTemplate != null) {
getTemplate.setAccessible(true);
tmpl = getTemplate.invoke(a.getClass(), id);
}
Object object = Proxy.newProxyInstance(b.getClass().getClassLoader(), b.getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("getNetworkTotalBytes")) {
return method.invoke(args[0], args[1], args[2], args[3]);
}
throw new RuntimeException("no method found");
}
});
Object[] args = {b.getClass(), tmpl, Long.MIN_VALUE, Long.MAX_VALUE};
stats = (long) ((b.getClass()) object).getState(args);
} catch (ClassNotFoundException e0) {
} catch (NoSuchMethodException e0) {
} catch (IllegalAccessException e0) {
} catch (InvocationTargetException e0) {
}
But it says that there is an error "Method call expected" in
stats = (long) ((b.getClass()) object).getState(args);
If I change this string like this
stats = (long) ((b) object).getState(args);
I get another error - "Unknown class: 'b'"

NoSuchMethodException loading Build.getRadioVersion() using reflection

I'm trying to load the radio version of the Android device using reflection. I need to do this because my SDK supports back to API 7, but Build.RADIO was added in API 8, and Build.getRadioVersion() was added in API 14.
// This line executes fine, but is deprecated in API 14
String radioVersion = Build.RADIO;
// This line executes fine, but is deprecated in API 14
String radioVersion = (String) Build.class.getField("RADIO").get(null);
// This line executes fine.
String radioVersion = Build.getRadioVersion();
// This line throws a MethodNotFoundException.
Method method = Build.class.getMethod("getRadioVersion", String.class);
// The rest of the attempt to call getRadioVersion().
String radioVersion = method.invoke(null).toString();
I'm probably doing something wrong here. Any ideas?
Try this:
try {
Method getRadioVersion = Build.class.getMethod("getRadioVersion");
if (getRadioVersion != null) {
try {
String version = (String) getRadioVersion.invoke(Build.class);
// Add your implementation here
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
Log.wtf(TAG, "getMethod returned null");
}
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
What Build.getRadioVersion() actually does is return the value of gsm.version.baseband system property. Check Build and TelephonyProperties sources:
static final String PROPERTY_BASEBAND_VERSION = "gsm.version.baseband";
public static String getRadioVersion() {
return SystemProperties.get(TelephonyProperties.PROPERTY_BASEBAND_VERSION, null);
}
According to AndroidXref this property is available even in API 4. Thus you may get it on any version of Android through SystemProperties using the reflection:
public static String getRadioVersion() {
return getSystemProperty("gsm.version.baseband");
}
// reflection helper methods
static String getSystemProperty(String propName) {
Class<?> clsSystemProperties = tryClassForName("android.os.SystemProperties");
Method mtdGet = tryGetMethod(clsSystemProperties, "get", String.class);
return tryInvoke(mtdGet, null, propName);
}
static Class<?> tryClassForName(String className) {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
return null;
}
}
static Method tryGetMethod(Class<?> cls, String name, Class<?>... parameterTypes) {
try {
return cls.getDeclaredMethod(name, parameterTypes);
} catch (Exception e) {
return null;
}
}
static <T> T tryInvoke(Method m, Object object, Object... args) {
try {
return (T) m.invoke(object, args);
} catch (InvocationTargetException e) {
throw new RuntimeException(e.getTargetException());
} catch (Exception e) {
return null;
}
}

In Java, how to use reflection to get a static method and execute it? [duplicate]

This question already has answers here:
How do I invoke a private static method using reflection (Java)?
(5 answers)
Closed 8 years ago.
I have a bunch of static method names, how do I execute them. I think I can use reflection, but how to do that?
directly from the interwebz
Class<?> class1;
try {
class1 = Class.forName(CLASS);
Method method = class1.getMethod(METHOD, String.class);
Object o = method.invoke(null, NAME);
System.out.println(o);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
Code to execute static method:
Method method = Utils.class.getMethod("generateCacheFolderName", Integer.class);
System.out.println(method.invoke(null, new Integer(10)));
and class with static method:
public class Utils {
public static String generateCacheFolderName(Integer len) {
Random rand = new Random();
StringBuilder sb = new StringBuilder(len);
for(int i = 0; i<len; ++i)
sb.append(rand.nextInt() % 10);
return sb.toString();
}
public static String anotherStaticMethod() {
return null;
}
}
static public Object execute( Class<?> cls, Object instance, String methodname,
Object[] args, Class<?>[] types ) throws Exception {
Object result = null;
Method met = cls.getMethod( methodname, types );
if (instance == null && !Modifier.isStatic( met.getModifiers() )) {
throw new Exception("Method '" + methodname + "' is not static, so "
+ "instance must be not null");
}
try {
result = met.invoke( instance, args );
}
catch (InvocationTargetException ite) {
throw (Exception) ite.getCause();
}
return result;
}

Categories

Resources