Reputation: 8606
I have a method from which i am returning object like
public static Object login(DataManager dataManager, String userName, String password)
ArrayList<LoginCredentialsBean> loginCredentialsList = new ArrayList<LoginCredentialsBean>();
String authenticated = "false";
Connection connection = null;
try {
connection = dataManager.getConnection();
} catch (Exception e) {
return ("Having problem in connectiong to databaste: " + e.getMessage());
}
if (connection != null) {
try {
...
try {
ResultSet rs = prepStatement.executeQuery();
try {
while (rs.next()) {
...
loginCredentialsList.add(new LoginCredentialsBean(roleId, orgaCode, passwordExpiryDate, date, status, language));
authenticated = "true";
} //end of while()
} finally {
rs.close();
}
} finally {
prepStatement.close();
}
if (authenticated.equals("true")) {
updateUserLogByInserting(connection, userName);
}
} catch(SQLException e) {
System.out.println("Could not login from dataabse:" + e.getMessage());
} finally {
dataManager.putConnection(connection);
}
}
if (authenticated.equals("true")) {
return loginCredentialsList;
} else {
return authenticated;
}
} //end of login()
Now i am testing it like
public static void main(String... args) {
MoneyTreeServices moneyTreeServices = new MoneyTreeServices();
Object result = moneyTreeServices.login("Admin", "cbas1234");
if (result instanceof ArrayList<?>) {
System.out.println("ArrayList instance");
}
System.out.println(result);
}
It returns me result like
ArrayList instance
[pk.mazars.moneyTree.bean.LoginCredentialsBean@b7ec5d]
I want to ask i am using condition like ArrayList<?>
. How can i check that ArrayList that contain LoginCredentialsBean object. Like when i use
if (result instanceof ArrayList<LoginCredentialsBean>) {
}
i get error that
Can not perform instanceof check against parameterized type ArrayList<LoginCredentialsBean>. Use the form ArrayList<?>
I want to check instanceof ArrayList and arraylist has LoginCredentialsBean ?
Thank you.
Upvotes: 0
Views: 791
Reputation: 103797
The short answer is that you can't. Generics are implemented via type erasure - they're effectively a compile-time syntactic sugar to ensure you don't put an Integer
into a List<String>
.
The runtime objects themselves, however, are just the raw types. An instance of ArrayList
doesn't know that it's an ArrayList<String>
(or rather, that it was assigned to a variable with that generic type). So when you interrogate it with reflection, you cannot get any generic type info.
There are two broad types of solution I can think of. One is to iterate over the list contents and check their dynamic type - if the first element is a LoginCredentialsBean
, for example, then it's reasonable to assume that you have a List<LoginCredentialsBean>
. This won't work for empty lists though, which could be a problem, and can potentially give false positives (e.g. a List<Object> allParameters
might happen to have a LoginCredentialsBean
as its first element...)
The other is to explicitly pass metadata objects around - so in this case you'd return the Object
from the login
method, along with a token which describes what type of object it is. This could be a simple enum constant; or going to the other extreme you could make the tokens generically typed, such that the compiler can check this against the type of what you're returning and ensure that the tokens are type-correct.
But in any case, instanceof
is too little (information), too late.
Mind you, your login
method looks... odd. I don't think it should return an Object
at all, as that's just lazy and completely subverting the static type system which would help you here. Rather, I think it should just return a List<LoginCredentialsBean>
containing the credentials that pertain to the given login.
You have three different paths where you return. The first is if an exception is encountered when connecting to the database - in which case you should throw an exception! Returning a string with the error details is very atypical and confusing - an exceptional condition should be handled as an Exception
, that's what they're for.
The other two situations are ones where you're able to look up definitive results. For the failed login case, I would just return an empty list (i.e. this username/password has no credentials whatsoever), while returning the populated list during a successful login.
If you strongly want to be able to distinguish between a login failure, and a successful login (with no credentials), then perhaps return a compound object instead, such as:
class LoginStatus {
final boolean authenticated;
final List<LoginCredentialsBean> credentials;
}
Either way, the caller knows exactly what they're getting back, and can call methods on it appropriately without having to call instanceof
and typecast.
Upvotes: 1
Reputation: 12212
If your login
method returns an Object
type there is no way to check this the way you try.
Type parameters exist only on compile-time due to type erasure. You need to check if retuned object is a List
or Collection
or just Iterable
, then iterate throuh it and check every item, if it is a instance of LoginCredentialsBean
.
However, your code is an example of bad design. A method that returns a String
or a list is just wrong. To make it right:
List<LoginCredentialsBean>
public static List<LoginCredentialsBean> login(DataManager dataManager, String userName, String password) throws AuthenticationException {...}
Note: Use boolean
to keep logical data instead of "true"
or "false"
strings.
Upvotes: 0
Reputation: 612
you can use the contains(Object o)
to check whether the ArrayList contains your object. With the instanceof List
to check whether the given object is a List. Because of type erasure at runtime the generic type of the List wont be available
Upvotes: 0
Reputation: 4712
There is no such thing like "ArrayList that contain LoginCredentialsBean" ArrayList contains Objects, all the time.
you must iterate over the list and check each object:
for (Object o: result) {
if (!(o instanceof LoginCredentialsBean)) {
//Fail
}
}
Upvotes: 0
Reputation: 1385
You have to check it twice.
if (result instanceof ArrayList<?>) {
System.out.println("ArrayList instance");
//cast
ArrayList<LoginCredentialsBean> list = (ArrayList<LoginCredentialsBean>) result;
///..check if list contains LoginCredentialsBean
for(int i=0; i<list.size(); i++){
if(list.get(i) instanceof LoginCredentialsBean){
System.out.println("LoginCredentialsBean instance");
}
}
}
Upvotes: 0
Reputation: 16060
Parameterized type info is erased at compile time and instanceof
is resolved at (fanfare) runtime - that is why you get that error.
What you could do is iterate over the elements in the List
and instanceof
them.
Cheers,
Upvotes: 1