How can I convert Entity to Object in java - java

I define a general List which can add any type elements, define as:List<List<Object>> rows = new ArrayList<>(); but when I get a list from my service layer, the compile process would throw a incompatible types exception, codes sample as below:
List<List<Object>> rows = new ArrayList<>();
List<ProductEntity> result = searchResponse.getProducts();
rows.add(result);
the exception is: incompatible types: java.util.List<com.shopee.data.webapispec.brandseller.entity.product.ProductEntity> cannot be converted to java.util.List<java.lang.Object> when I run the command "mvn clean install", anyone knows how to handle it?

ProductEntity is a sub class of Object. However List<ProductEntity> is not a subclass of List<Object>.
You need to have List<List<? extends Object>> rows = new ArrayList<>(); to make this work.
See here for details on Generics and Object Hierarchies

Related

Why Java doesn't allow me to add subclass istances?

I have a problem in a Java project.
The code where error born is the following:
HashMap<String, LinkedList<? extends User>> signedUpUsers =
new HashMap<>(Map.of(
"Administrator", new LinkedList<Administrator>(),
"Employee", new LinkedList<Employee>(),
"Customer", new LinkedList<Customer>()));
for (String userName : userNameList)
{
userPropertyValue = usersProperties.getProperty(userName).split(",");
String password = userPropertyValue[0].replaceAll("\\s", "");
String role = userPropertyValue[1].replaceAll("\\s", "");
if (role.equals("Administrator"))
{
signedUpUsers.get("Administrator").add(new Administrator(userName, password));
}
else if (role.equals("Customer"))
{
signedUpUsers.get("Customer").add(new Customer(userName, password));
}
else
{
signedUpUsers.get("Employee").add(new Employee(userName, password));
}
}
It gives me an error when I try to add new elements in each list of hashmap, when I create instances, intellij tells me:
Required type: capture of ? extends User
Provided: Customer (or Employee or Administrator)
But why, if Customer, Employee and Administrator are all subclasses of User?
What I should change? My intention is to have an HashMap which contains all signed up users (I saved them in a .properties file which is corrected red because I saw that), where keys are roles of users (Administrators, Employees and Customers), and the value of each key is a LinkedList of each user with that role.
I also tried to use super instead of extends, but in that case I solve this error, but a new error appear in creating the hashmap with Map.of() (because Administrator, Customer and Employee aren't superclass of User).
The code works if I have 3 different lists declared directly with 3 roles objects, but I wanted the hashmap because I want to return the whole signed up users divided by their role.
Thanks to all, I hope I was clear in explaining.
The reason for the compiler error has been covered in #Thomas's comment: To the compiler, signedUpUsers.get("Administrator") is a LinkedList<? extends User>, not knowing that under the "Administrator" key, you stored a LinkedList<Administrator> (and not e.g. a LinkedList<Employee>, so the compiler does not allow adding an Administrator.
Your signedUpUsers variable shows some significant generics over-engineering. You declare
HashMap<String, LinkedList<? extends User>> signedUpUsers =
new HashMap<>(Map.of(
"Administrator", new LinkedList<Administrator>(),
"Employee", new LinkedList<Employee>(),
"Customer", new LinkedList<Customer>()));
I suggest to change that to
HashMap<String, LinkedList<User>> signedUpUsers =
new HashMap<>(Map.of(
"Administrator", new LinkedList<User>(),
"Employee", new LinkedList<User>(),
"Customer", new LinkedList<User>()));
You might ask "But now I don't have the type safety that I can only store Administrator instances under the "Administrator" key." But that type safety also wasn't possible with the first version (at run-time, the LinkedList<Administrator> is just a LinkedList and will happily accept any Object, and at compile-time LinkedList<? extends User> will not allow adding anything).
If you want type safety for the lists, throw away the Map approach, and create a class UserList:
public class UserList {
private List<Administrator> administrators;
private List<Employee> employees;
private List<Customer> customers;
// add constructor, getters, adders etc. here
}
This will easily give the desired type safety.

convert List of hashmap into set

i want to cast List<HashMap<String, Object>> into Set<StudentInfo>
i have method
public List<HashMap<String,Object>> getStudentData(studentId);
i want to convert the result into Set so i used
Set<StudentInfo> studentFilteredInfo = new HashSet<>();
List<Map<String, Object>> studentCompleteRecord = getStudentData(1005);
studentFilteredInfo.addAll((Collection<? extends StudentInfo>studentCompleteRecord ));
initially when i executed on localhost it with java 8, eclipse and tomcat 8 it is working fine.
when i tried to build it with maven
mvn clean package
it will through an Error:
incompatible types: java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
cannot be converted to java.util.Collection<? extends com.school.model.StudentInfo>
You are mistaken: there is no casting from List<Map<String, Object>> into some Set<Whatever>!
Casting basically means: you know that some "Object" has a more specific type; thus you tell the compiler: "you can safely assume that this thingy here is something else in reality".
But that means: in reality (at runtime), that "thingy" really is "something else"! And alone the generic types that you provide in your question make it very clear: you can't be doing a cast here!
In other words: you have to write code that iterates your List of Maps; to extract that information that is required to create new StudentInfo objects. Then you collect those newly created objects; and put them into a new Set; which you then can return from your method!
And finally: always avoid "concrete" implementation types; you used List<HashMap<... - instead, you should go for List<Map<... !
You need to write code to explicitly convert a Map<String,Object> to a StudentInfo instance. Suppose StudentInfo has a method like this:
static StudentInfo create(Map<String, Object> info) {
String name = info.get("name");
Transcript transcript = info.get("grades");
return new StudentInfo(name, transcript);
}
Then you would need to iterate over each element in the list and use your method to convert the Map instances to StudentInfo objects.
With lambdas:
Set<StudentInfo> studentFilteredInfo = studentCompleteRecord.stream()
.map(StudentInfo::create)
.collect(Collectors.toSet());
Without lambdas:
Set<StudentInfo> studentFilteredInfo = new HashSet<>();
for (Map<String,Object> e : studentCompleteRecord)
studentFilteredInfo.add(StudentInfo.create(e);

How to convert List<?> to List<className>

I am facing some problem when converting list to List
List<ContentDes> contentDes_ls = new ArrayList<ContentDes>();
logger.info("in getContentDes ");
List<?> ls = ho.getResultListByLimit(sql,limit);
contentDes_ls = (List<ContentDes>)ls;
logger.info(" size of content "+contentDes_ls.size());
for (ContentDes contentDes : contentDes_ls) {
logger.info(contentDes.getPricetag());
logger.info(contentDes.getPrv());
}
Its worked fine when I get the size of List<SomeClass> but when I
access the getter and setter of SomeClass I got exception
Output:
size of content 2
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to com.SomeClass]
SomeClass is not mentioned anywhere in your code, so I assume you mean ContentDes.
It appears your list doesn't contain ContentDes instances. The Exception indicates the items are instead of type Object[]. This causes a ClassCastException when you try to iterate over the items as ContentDes.

Creating instance list of different objects

I'm tring to create an arraylist of different class instances. How can I create a list without defining a class type? (<Employee>)
List<Employee> employees = new ArrayList<Employee>();
employees.add(new Employee());
Employee employee = employees.get(0);
You could create a list of Object like List<Object> list = new ArrayList<Object>(). As all classes implementation extends implicit or explicit from java.lang.Object class, this list can hold any object, including instances of Employee, Integer, String etc.
When you retrieve an element from this list, you will be retrieving an Object and no longer an Employee, meaning you need to perform a explicit cast in this case as follows:
List<Object> list = new ArrayList<Object>();
list.add("String");
list.add(Integer.valueOf(1));
list.add(new Employee());
Object retrievedObject = list.get(2);
Employee employee = (Employee)list.get(2); // explicit cast
List<Object> objects = new ArrayList<Object>();
objects list will accept any of the Object
You could design like as follows
public class BaseEmployee{/* stuffs */}
public class RegularEmployee extends BaseEmployee{/* stuffs */}
public class Contractors extends BaseEmployee{/* stuffs */}
and in list
List<? extends BaseEmployee> employeeList = new ArrayList<? extends BaseEmployee>();
List anyObject = new ArrayList();
or
List<Object> anyObject = new ArrayList<Object>();
now anyObject can hold objects of any type.
use instanceof to know what kind of object it is.
I believe your best shot is to declare the list as a list of objects:
List<Object> anything = new ArrayList<Object>();
Then you can put whatever you want in it, like:
anything.add(new Employee(..))
Evidently, you will not be able to read anything out of the list without a proper casting:
Employee mike = (Employee) anything.get(0);
I would discourage the use of raw types like:
List anything = new ArrayList()
Since the whole purpose of generics is precisely to avoid them, in the future Java may no longer suport raw types, the raw types are considered legacy and once you use a raw type you are not allowed to use generics at all in a given reference. For instance, take a look a this another question: Combining Raw Types and Generic Methods
How can I create a list without defining a class type? (<Employee>)
If I'm reading this correctly, you just want to avoid having to specify the type, correct?
In Java 7, you can do
List<Employee> list = new ArrayList<>();
but any of the other alternatives being discussed are just going to sacrifice type safety.
If you can't be more specific than Object with your instances, then use:
List<Object> employees = new ArrayList<Object>();
Otherwise be as specific as you can:
List<? extends SpecificType> employees = new ArrayList<? extends SpecificType>();
I see that all of the answers suggest using a list filled with Object classes and then explicitly casting the desired class, and I personally don't like that kind of approach.
What works better for me is to create an interface which contains methods for retrieving or storing data from/to certain classes I want to put in a list. Have those classes implement that new interface, add the methods from the interface into them and then you can fill the list with interface objects - List<NewInterface> newInterfaceList = new ArrayList<>() thus being able to extract the desired data from the objects in a list without having the need to explicitly cast anything.
You can also put a comparator in the interface if you need to sort the list.
I know this is an old question, but there's a nice and easy way to do this (it works with the mostly recent versions of ElasticSearch Rest API).
The search object goes like:
SearchResponse<JsonData> search = client.search(s -> s
.index(index)
.query(query),
JsonData.class);
And then I iterate over the response like this:
for (Hit<JsonData> hit: search.hits().hits()) {
String stringSource = hit.source().toString();
MySavedRegister mySavedRegister = mapper.readValue(stringSource, mySavedRegister .class);
mylist.add(esGenericEvent);
}
Where mySavedRegister stands for the class that has the hits' sources parameters.

What causes this retainAll exception?

java.lang.UnsupportedOperationException: This operation is not supported on Query Results
at org.datanucleus.store.query.AbstractQueryResult.contains(AbstractQueryResult.java:250)
at java.util.AbstractCollection.retainAll(AbstractCollection.java:369)
at namespace.MyServlet.doGet(MyServlet.java:101)
I'm attempting to take one list I retrieved from a datastore query, and keep only the results which are also in a list I retrieved from a list of keys. Both my lists are populated as expected, but I can't seem to user retainAll on either one of them.
// List<Data> listOne = new ArrayList(query.execute(theQuery));
// DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
// List<Data> listTwo = new ArrayList(ds.get(keys).values());
// listOne.retainAll(listTwo);
EDIT
Ok, in an attempt to simplify, since this is apparently multiple problems in one, I have stopped using the low level API for datastore and instead of am just pulling one by one with a loop.
List<MyClass> test = (List<MyClass>) query.execute();
List<MyClass> test2 = new ArrayList<MyClass>();
for (String key : favorites) {
test2.add(pm.getObjectById(MyClass.class, key));
}
log.info(test.toString());
test.retainAll(test2);
The above works. It doesn't throw the exception. The below does throw the exception. The only difference is the log.info. I'm stumped.
List<MyClass> test = (List<MyClass>) query.execute();
List<MyClass> test2 = new ArrayList<MyClass>();
for (String key : favorites) {
test2.add(pm.getObjectById(MyClass.class, key));
}
test.retainAll(test2);
It will not let me do new ArrayList() on the query result since it returns an array of objects.
You however need to put them in a new ArrayList(). The returned List implementation apparently doesn't support retainAll(). That's what the exception is telling you.
A "plain" ArrayList supports it. If passing through the ArrayList constructor is not possible due to difference in generic type, then you'll need to manually loop over it and cast each item before adding.
List<Data> listTwo = new ArrayList<Data>();
for (Object object : ds.get(keys).values()) {
listTwo.add((Data) object);
}
listOne.retainAll(listTwo);
Update: as per your update, the entities are apparently lazily loaded/filled. Most ORM's (DataNucleus is one) may indeed do that. As I don't use DataNucleus, I can't go in detail how to fix that in a "nice" way. But you at least now know the root cause of the problem and it can be solved the same way as above. Fill the list test in a loop as well.
If the type of collection you use for your "list of keys" does not support retainAll that exception will be thrown. Which type are you using?
TIP: you don't need to iterate to fill listTwo.
just do:
listTwo.addAll(ds.get(keys).values())

Categories