Dynamic Class casting - java

I'm having a problem with casting in Android.
I'm developing an App that handle multiple devices, and i'm trying to make a dynamic class alocation (i.e, User sets the device and the app instanciate the class according to the user settings)
Here is a Sample code:
String Usr_imput; //name of the class
Class class = Class.forName(Usr_Input);
Object o = class.newInstance();
with that I can't access methods from the Usr_Input Class. The method class.cast(o) should be the solution to my problems but I can't get it to work, does the cast statement stacks?
Isn't it suposed to work if I use:
class.cast(o);
o.Method();
Anyone has experience on that?

Usr_Input o = (Usr_Input)class.newInstance();

from java doc:
cast
public T cast(Object obj)
blahblah..
Returns:
the object after casting, or null if obj is null
From your codes, you didn't catch the return value. class is not a good name either. check the comment above.
class.cast(o);
o.Method();

Related

Use a generic type to pass a specific class

I'm very new to programming language. My question might not even make sense. My environment is using java and trying to implement both ios and android apps in the same automation testing framework.
So, the idea is that any test script should be able to run on both the apps. Ex: one signin test script should be run for both ios and android.
I've decided to use interface and class implementation approach. The problem I'm facing is with test data. My company doesn't want to use excel. They want to use json for test data.
Here's my problem, look at the following line of code:
ValidBuy goodBuy = JsonFileReader.loadDaTa(TestBase.DATA_PATH, "good-buy.json", ValidBuy.class);
As you can see I have a class "ValidBuy" that has all the getters for a particular json file. I have another class "JsonFileReader" which takes the json filePath, fileName, and a class as an input and returns the data for that class name that I passed in. For this example I've passed ValidBuy.class
So, when I run a positive test, I'm passing "goodBuy" variable which is of type "ValidBuy". The problem starts here.
The test case is now specified with the data from goodBuy because it's type is "ValidBuy" and I'm passing goodBuy as a parameter.
Look at one of my extracted methods:
private void enterBuyInfo(ValidBuy goodBuy) {
itemPage = nativeApp.getItemPage(goodBuy);
itemPage.setItemName(goodBuy.getItemName());
itemPage.setItemSize(goodBuy.getItemSize());
itemPage.setItemDigitSSN(goodBuy.getSsn());
itemPage.clickContinue();
}
You can see those getters I'm using are coming from ValidBuy class.
If I run this test with the data for a badBuy:
InvalidBuy badBuy = JsonFileReader.loadDaTa(TestBase.DATA_PATH, "bad-buy.json", InvalidBuy.class);
It fails because now I have to change "ValidBuy" class with "InvalidBuy" class. Since, changing the parameter in the extracted method in every run is not possible, how can I make it more generic?
I want something like this:
TestData data = JsonFileReader.loadDaTa(RESOURCES_PATH, "good-client.json", InvalidBuy.class);
Here, TestData is generic. It could either be a class or interface (I don't know if that's possible) and the return type will be specified by whichever class I pass into the loadData() method. In this case InvalidBuy.class
The extracted method should look like this:
private void enterBuyInfo(TestData data) {
itemPage = nativeApp.getItemPage(data);
itemPage.setItemName(data.getItemName());
itemPage.setItemSize(data.getItemSize());
itemPage.setItemDigitSSN(data.getSsn());
itemPage.clickContinue();
}
If I can do this, I can use those extracted methods to create more tests.
I know I wrote a lot. I've only tried to make it as clear as possible. If it doesn't make any sense, just disregard it.
Any suggestions, ideas, code samples will be highly appreciated.
Firstly let me see if I understand your question. I think you are saying that loadData may return a value of type ValidBuy or InvalidBuy and you want to pass into it the class that you want returned. You then want to know how to use an interface that might represent either of these classes in your test methods so you can test various return values (both valid and invalid). You use the term "generic" in your question but I'm guessing you don't mean to use it in the specific way it's used in Java.
If I've understood your question correctly, then here's an answer:
Passing the class you wish to have returned into a method is an unusual usage and almost certainly not ideal. Better OOD would be to extract the common methods for all objects returned from loadData into an interface.
So:
interface Buy {
String getItemName();
boolean isValid();
}
class ValidBuy implements Buy {
#Override
public boolean isValid() {
return true;
}
...
}
class InvalidBuy implements Buy {
#Override
public boolean isValid() {
return false;
}
...
}
class JsonFileReader {
Buy loadData(Path path) {
...
}
}
Then your tests can look like:
#Test
void testValidBuy() {
assertTrue(reader.loadData(validPath).isvalid());
}
#Test
void testInvalidBuy() {
assertFalse(reader.loadData(invalidPath).isValid());
}
I realise I've simplified it a bit but hopefully you get the idea.

Java : method that takes in argument any attribute of any class

I need to create a method that takes in argument any attribute of any class. But i dont want it to be of type String, to avoid refactoring problems while renaming an attribute and to get the errors in Markers Tab of eclipse, and not while running my application.
Having a class Person :
public class Person {
private String name;
// other attributes...
// getters and setters...
}
Now the needed method :
void getAnAttributeOfAClass( <which_type_or_class_here?> attr_as_arg){
// Now I need to get the name of attribute that would be of class Strin...
}
Is there a function or a method, by which we can specify an attribute?
For example :
Person.class.name
Would it be of class Property ?
EDIT
More exactly (#Smallhacker answer helped me), I need to verify at compile time if the argument is really an attribute of the specified class.
Person.class.name // no compile time error
Person.class.nameXXX // compile time error
The closest to what you want is Reflection API's Field or JavaBeans Introspector API's PropertyDescriptor.
But usually things like that are not needed in Java projects because there are libraries which handle these concerns.
You could pass a Class object along with a String name, then let your method use Introspector internally to read that property.
Not sure I understand you well, but there is a class java.lang.reflect.Field, that has a method getName() that would give your the name of the field.
In your example, to get field name, you would do: Person.class.getDeclaredField("name").
EDIT: to get the value of a field in an object, you would do: field.get(obj);
OK, let's say You have the following variables:
Person person = ...; // initialized with some Person
Field nameField = Person.class.getDeclaredField("name");
Now to get the name of person, you would do:
String personName = (String)nameField.get(person);
Actually, this would throw an exception because name is a private field. You can however bypass the protection by doing:
nameField.setAccessible(true);
Unfortunately, Java lacks an ability to reference member variables in a way that can be analyzed at compile time.
There may be some kind of library to simplify this somewhat, but it wouldn't provide a full solution due to limitations in the language itself.
Maybe java generics can help you with this.
You can do something like:
class YourClass<E> {
void getAnAttributeOfAClass(E attr_as_arg){
// some code
}
}
someVariable = new YourClass<Person>();
someVariable.getAnAtributeOfAClass(someObject); //this will not compile if someObject is not an instance of Person
But I still don't know what you want to do exactly inside the method.

What does `Client.findById(id)` mean?

Looking through the Play documentation for Java I noticed the following block of code:
public static Result show(Long id) {
Client client = Client.findById(id);
return ok(views.html.Client.show(client));
}
Source: http://www.playframework.com/documentation/2.1.0/JavaRouting
I am having some trouble understanding the second line, my understanding of Java Object creation is a typical constructor looks like the following:
Person john = new Person();
What is the second line doing? Creating a Object called client from Class called Client, also what is Client? It doesn't appear to be a part of the Play Framework, certainly I cannot find anything in JavaDocs.
Thanks
Edit:
I found this to be a good point of reference for the answer (http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html)
Also I think the class Client comes from the following documentation (http://www.playframework.com/documentation/1.1.1/controllers) with Client being just a example model class, the new documentation probably needs updating to clear up this confusion.
Pretty clearly, the class Client has a static function of findById, which takes a Long and returns a Client. Static functions are functions that are defined without any access to object properties, and therefore can be accessed through the class name, rather than having to be accessed through an object. Most likely, the class has a static property containing a collection of all clients in the system by index, and findById grabs an existing Client from that list.
I really have no idea where the class Client is defined, however. I've also made a quick look around for it, and couldn't find it in the obvious places.
There must be a static method called show(Client) on the views.html.Client class that returns some object. That object is passed into an ok(whatever) method, and that ok method returns a Result object.
You're missing some basic knowledge/experience. The sample you gave has nothing to do with routes and in this snippet only first line is important, second is just some hypothetical usage. De facto it could be just...
public static Result show(Long id) {
return ok("You want to display details of client with ID: " + id);
}
Although #BenBarden explained what is that mean correctly , this static method isn't declared anywhere, it's (again) hyphotetical usage of some ORM. For an example the real usage with Ebean's model will be:
Client = Client.find.byId(id);
Of course you can also declare own method in your Client model and name it the same as in the sample, however it will be just only wrapper:
public static Finder<Long, Client> find
= new Finder<>(Long.class, Client.class);
public Client findById(Long id) {
return find.byId(id);
}
Conclusions
You need to examine some samples available with your Play sources to get familiar with some basic syntax, fortunately you'll find it easy.
DO NOT MIX documentation from Play 1.x with Play 2.x they are not compatible!

ClassCastException error when casting back to original class

I have the following code:
public void doJob() {
MyObj s;
for ( Object o : MyObj.all().fetch()) {
s = (MyObj) o; // ClassCastException here
if (!s.fileExists()) {
//Do some stuff
}
}
}
which is throwing this exception:
play.exceptions.JavaExecutionException: models.MyObj cannot be cast to models.MyObj
at play.jobs.Job.call(Job.java:155)
at Invocation.Job(Play!)
Caused by: java.lang.ClassCastException: models.MyObj cannot be cast to models.MyObj
at jobs.OrphanSurveys.doJob(OrphanSurveys.java:18)
at play.jobs.Job.doJobWithResult(Job.java:50)
at play.jobs.Job.call(Job.java:146)
... 1 more
(This method runs inside a Play Job class, if that matters.)
The MyObj.all().fetch() is returning an Iterable of some kind containing all of the MyObj objects in the database. MyObj inherits this method from the Play! Framework's Model class, if that matters. That's why it's returning a list of Objects rather than MyObjs, and I can't change how it works.
So, is there some reason that I can't cast back to MyObj? I can see how there would be some weirdness casting back from an Object, but Java seems to know what the class of the object used to be.
Thanks!
It looks like you have ClassLoader issues. The objects being returned by your fetch() method were loaded in a different ClassLoader than the one being used in the current thread to try and cast.
Try this to confirm. Add the three lines of code to your exising code.
for ( Object o : MyObj.all().fetch()) {
// Check classloaders
System.out.println(o.getClass().getClassLoader());
System.out.println(MyObj.class.getClassLoader());
break;
//
s = (MyObj) o; // ClassCastException here
if (!s.fileExists()) {
//Do some stuff
}
}
I saw a recent post here on StackOverflow that indicated that if two otherwise identical instances of the same class are loaded by different classloaders, you cannot cast between them.
Post in question
Check whether you are not subject to the multiple classloader condition here too.
From your stack trace, apparently, there's some other kinds of entries in your collection.
Use o.getClass().getName() inside your loop to know what is .all().fetch() really returning.
Note: Maybe some model.Survey objects?

Java Using Strings as Code

Okay, so, here's what I have in code:
public void makeObject(int i){
String s = getString(i); //This returns the name of a class
new s(); //This is what I want to do
}
Can I do this?
No you can't do this, but what you're probably looking for is called 'reflection'.
Look at these series of (free) slides: http://www.slideshare.net/CiaranMcHale/java-reflection-explained-simply especially slide 11, but read the ones before that as well. It will give you an idea of what reflection is and a way to make a class by knowing the name (as a string) and how to instantiate a new instance of that class.
You can also find methods and fields by name, you can even modify existing classes in code.
Edit: for example the following code will return a class by string name
Class cls = Class.ForName("MyPackage.MyClassName");
return cls.NewInstance();

Categories