Dynamically set List<type> - java

I have previously only used reflection to do things like dynamically get class and set field values in it. My Google search showed me that I could also possibly use reflection for dynamic type casting?
My code is as follows:
import entity.Shipvia;
import entity.Route;
import java.lang.reflect.Field;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Persistence;
import javax.persistence.Query;
public class RetrieveResultList {
public static List retrieveResultList(String tablename) {
EntityManager entityManager = Persistence.createEntityManagerFactory("EntityLibraryPU").createEntityManager();
Query query = entityManager.createNamedQuery(tablename + ".findAll");
List<Shipvia> resultList = query.getResultList();
return resultList;
}
}
I am using this method to dynamically retrieve result from a database table. Because the table name is always different, I cannot have List as it will be different for each table.
How would I go about converting the tablename string that I am passing in, to be the type of the List?

You can't do that and even if you could, it would be useless as all generics information is removed from the Java code when it's compiled, only casts would be there and as you would be using reflection there would be no casts to be made.
The closest thing you will be able to do is, instead of sending in a String send a Class object. The caller code would have to say which class it wants (the caller probably knows what kind of object it's using) and you would use it to make the list have the correct generic.
A very simple implementation would be something like this:
List<Shipvia> shipvias = RetrieveResultList.retrieveResultList( Shipvia.class );
And implementation could be something like this:
public class RetrieveResultList {
private static final EntityManagerFactory FACTORY = Persistence.createEntityManagerFactory("EntityLibraryPU");
public static <T> List<T> retrieveResultList(Class<T> type) {
EntityManager entityManager = FACTORY.createEntityManager();
String tablename = type.getName(); // figure out table name from **type**
Query query = entityManager.createNamedQuery(tablename + ".findAll");
List<T> resultList = query.getResultList();
entityManager.close();
return resultList;
}
}
And then you should have something like what you're looking for.
ALSO, DO NOT create an entity manager factory on every call to this method, the entity manager factory MUST BE a singleton in your project as it's a very expensive object to create. You should also close the EntityManager you created before leaving the method.

Related

trying to set a member ArrayList using reflection

I am trying to modify an object with an Arraylist of objects using reflection.
I understand that I cannot get the type of the objects in the ArrayList, but I (think) I am using an annotation to handle that part. I am setting the field accessibility.
I am declaring the list of stuff in the class using annotations.
#TableAnnotation(type = PhoneNumber.class)
protected List<PhoneNumber> phoneNumbers = new ArrayList<>();
#TableAnnotation(type = Address.class)
private List<Address> addresses= new ArrayList<>();
private List<Role> roles= new ArrayList<>();
... Later in the same class I try to set them:
public void setMemberTable(List<Table> tables, String memberName) throws IllegalAccessException {
Class t = getClass();
for (Field field : getClass().getDeclaredFields()) {
if (field.getName() == memberName) {
field.setAccessible(true);
List array = (List)field.get(this.getClass()); <<<=========== Here is where it is throwing
ArrayList arrayList= (ArrayList)field.get(this.getClass());
//array.add(tables.get(0));
System.out.println();
}
}
}
Here is the Annotation that seems to be working:
package com.test.database.helpers;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Documented
#Target(ElementType.FIELD)
#Inherited
#Retention(RetentionPolicy.RUNTIME)
public #interface TableAnnotation {
Class< ?> type();
boolean allowNull() default false;
}
This throws:
java.lang.IllegalArgumentException: Can not get java.util.List field com.test.database.entities.Person.phoneNumbers on java.lang.Class
I tried making the member variable public, but that had no affect.
I need help to be able to set the member variables in setMemberTable().
(List)field.get(this.getClass());
The .get method on j.l.reflect.Field requires the instance that you want to get the field from. You're passing the class. Which is an object of type java.lang.Class, which, of course, does not have this field, and therefore, you can't get the value of it. You want this instead.
Actually, none of this makes sense, you're right there, just read your own field. I assume this is test code, but if not, none of this makes sense in the first place.
You ask the wrong object for the value of the field.
When you write
field.get(this.getClass())
you try to get the value that the (reflected) field has on some instance. The object that you pass to retrieve the value from is this.getClass() which is an instance of java.lang.Class - and java.lang.Class has no field (for example) "phoneNumbers".
To retrieve a field from your instance you must write
field.get(this)
But then, the commented out line
array.add(tables.get(0));
doesn't make any sense. Why do you try to add an element from the tables list (which is an instance of Table) to a list of (for example) "phoneNumbers", which is a list of PhoneNumber?
And your claim that the annotation works: I don't see that annotation used anywhere in your code, so it is hard to say whether it works or not...

Java generics and reflection to create and set model for SimpleJdbcCall in Spring

I am trying to use reflection and generics to create models using SimpleJdbcCall. At the moment I have to create a distinct mapper per model that I add to the project. I would like to create a mapper that uses reflection to just simply map the model, so that I only have to write one mapper (in the method below).
Here is my implementation so far:
#Repository
public abstract class DAO<T extends ModelBase> {
private final DataSource dataSource;
DAO(final DataSource dataSource) {
this.dataSource = dataSource;
}
protected List<T> buildModels(SqlParameterSource sqlSource, Class modelBase) {
final String RESULT_SET = "RESULT_SET";
return (List<T>)new SimpleJdbcCall(dataSource)
.withCatalogName("someCatalog")
.withSchemaName("someSchema")
.withProcedureName(getProcForModel(modelBase))
.returningResultSet(RESULT_SET, (ResultSet rs, int rowNum) -> {
/*
1. get an actual instance of the modelBase reference that is passed in
2. get references to the setters of the modelBase instance
or be able to pick out where to set things in the constructor of the modelBase
3. loop thru ResultSet, setting parameters on model where the name of the
setter or constructor arg matches the name of the column in the resultSet
*/
}).execute(sqlSource).get(RESULT_SET);
}
}
The modelBase class referenced passed in would obviously be a class that inherits from the abstract ModelBase class.
The issues I have enumerated above are the things that I have not been able to figure out how I am supposed to do using the Reflection API in Java. Does anyone know how to do what I am trying to achieve?
Also, some of the values coming from the resultSet might not be Strings, but rather things like Dates and boolean. How would I reflectively call the right method on the resultSet? i.e. getInts() or getDate() or getBoolean(), etc.

EntityManagerProvider is injected as null

I'm using the ninja framework, which utilizes JPA to access a database.
I've managed to set up a connection and get it running in an example controller class.
I'd like to model a "userManager" which, upon initialization, loads all current users from the database into a java map.
When doing so, I face a java.lang.NullPointerException upon calling entitiyManagerProvider.get() since entitiyManagerProvider is set to null.
I'm not sure what is causing this problem and how to solve it, as the "UserManager" has the same annotations as my (problem-free) test controller. Since I don't have any experience with ninja or JPA it might be a very simple fix I simply overlook and I'd appreciate any help.
This is the code for "UserManager.java":
package model;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import com.google.inject.Inject;
import com.google.inject.Provider;
import dto.UserDTO;
import ninja.jpa.UnitOfWork;
public class UserManager {
#Inject
Provider<EntityManager> entitiyManagerProvider;
private static UserManager instance;
private Map<Integer, UserDTO> users = new HashMap<Integer, UserDTO>();
//UserManager is a Singleton
public static synchronized UserManager getInstance(){
if (UserManager.instance == null){
UserManager.instance = new UserManager();
}
return UserManager.instance;
}
private UserManager() {
// load all existing users to map
reloadUsersFromDb();
}
public int getAmountUsers(){
return users.values().size();
}
/**
* reloads ALL users in the map from the db
*/
#UnitOfWork
private void reloadUsersFromDb() {
if (entitiyManagerProvider == null) {
System.out.println("provider is null"); //this is printed
} else {
System.out.println("provider is NOT null"); //not printed
}
EntityManager entityManager = entitiyManagerProvider.get();
//^-- causes null Pointer exception
Query q = entityManager.createQuery("SELECT users FROM users");
List<UserDTO> dbUsers = q.getResultList();
int loadedUsers = 0;
users.clear();
for (UserDTO dbUser : dbUsers) {
users.put(dbUser.getId(), dbUser);
loadedUsers++;
}
System.out.println("loaded " + loadedUsers + "users from db to applicaton.");
}
}
The problem is that injection does never work with objects created directly using new keyword. And this is what you are doing in the getInstance() method. Also you should not depend on injected values in the constructor, as they are injected only after the object is created.
To turn on injection, the instance of UserManager must be created by the framework. Controllers are automatically created by the framework, therefore injection works there.
To fix your code, you could create a service out of UserManager, remove call to reloadUsersFromDb from constructor and mark this method to run at startup with #Start as described here in Ninja framework documentation

Does setDefaultHighRepJobPolicyUnappliedJobPercentage(100) really work?

According to https://cloud.google.com/appengine/docs/java/tools/localunittesting#Writing_HRD_Datastore_Tests, "If your app uses the High Replication Datastore (HRD), you may want to write tests that verify your application's behavior in the face of eventual consistency. LocalDatastoreServiceTestConfig exposes options that make this easy." You're supposed to set setDefaultHighRepJobPolicyUnappliedJobPercentage(100) and then, "By setting the unapplied job percentage to 100, we are instructing the local datastore to operate with the maximum amount of eventual consistency. Maximum eventual consistency means writes will commit but always fail to apply, so global (non-ancestor) queries will consistently fail to see changes."
However, I don't think setDefaultHighRepJobPolicyUnappliedJobPercentage(100) works.
If it did, then my test case below, testEventualConsistency() should pass but it it fails on the second assertion. On the first assertion, I read back an object I've saved using an Objectify ancestor() query. It works as documented because the object is retrieved. However, the second assertion fails. In that assertion I've also read back the object I've saved but I haven't used an Objectify ancestor() query so it shouldn't retrieve anything because I've specified that no jobs should complete (i.e. the setDefaultHighRepJobPolicyUnappliedJobPercentage(100) setting).
EventualConsistencyTest Test Case
import static com.googlecode.objectify.ObjectifyService.begin;
import static com.googlecode.objectify.ObjectifyService.ofy;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import java.util.List;
import org.junit.Test;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.Ref;
import com.googlecode.objectify.util.Closeable;
import com.netbase.followerdownloader.model.DownloadTask;
import com.netbase.followerdownloader.model.User;
public class EventualConsistencyTest {
private final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig()
.setDefaultHighRepJobPolicyUnappliedJobPercentage(100));
#Test
public void testEventualConsistency() {
helper.setUp();
ObjectifyRegistrar.registerDataModel();
User user = new User();
user.id = 1L;
Closeable closeable1 = begin();
ofy().save().entity(user);
closeable1.close();
Closeable closeable2 = begin();
DownloadTask downloadTask = new DownloadTask();
downloadTask.owner = Ref.create(user);
ofy().save().entity(downloadTask);
closeable2.close();
Closeable closeable3 = ObjectifyService.begin();
List<DownloadTask> downloadTasks1 = ofy().load().type(DownloadTask.class).ancestor(user).list();
assertThat(downloadTasks1.size(), equalTo(1));
closeable3.close();
Closeable closeable4 = ObjectifyService.begin();
List<DownloadTask> downloadTasks2 = ofy().load().type(DownloadTask.class).list();
assertThat(downloadTasks2.size(), equalTo(0)); // THIS SHOULD PASS IF setDefaultHighRepJobPolicyUnappliedJobPercentage(100) WORKED
closeable4.close();
helper.tearDown();
}
}
User Definition
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
#Entity
public class User {
#Id public Long id;
public User () {
}
}
DownloadTask Definition
import com.googlecode.objectify.Ref;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Parent;
#Entity
public class DownloadTask {
#Id public Long id;
#Parent public Ref<User> owner;
public DownloadTask() {
}
}
Environment:
appengine-api-1.0-sdk-1.9.17.jar
appengine-testing-1.9.17.jar
appengine-api-stubs-1.9.17.jar
junit-4.11.jar
objectify-5.1.3.jar
In case I missed anything else important, here is a more exhaustive list:
My questions are:
Is setDefaultHighRepJobPolicyUnappliedJobPercentage(100) broken?
Does setDefaultHighRepJobPolicyUnappliedJobPercentage(100) not really work as documented? Does it in fact apply the job even though the documentation says it's not supposed to?
Is the value passed to setDefaultHighRepJobPolicyUnappliedJobPercentage() really supposed to be 100 and not maybe let's say, 1.0f?
Do Objectify ancestor queries not really work as documented?
The problem is explained by an observation at https://cloud.google.com/appengine/docs/java/tools/localunittesting#Java_Writing_High_Replication_Datastore_tests :
"In the local environment, performing a get() of an Entity that belongs to an entity group with an unapplied write will always make the results of the unapplied write visible to subsequent global queries."
In this contect, this means the ancestor-query:
List<DownloadTask> downloadTasks1 = ofy().load().type(DownloadTask.class).ancestor(user).list();
which internally "performs a get() of an Entity that belongs to an entity group with an unapplied write" influences the behavior of the immediately-following global query:
List<DownloadTask> downloadTasks2 = ofy().load().type(DownloadTask.class).list();
To avoid your tests influencing each other, and in particular, interfering w/each other in this way, it's best to use a separate method per operation under test (each with all the needed setup and teardown parts), rather than having successive operations-under-test within a single test method.

Error in 'and' method of Hibernate Criteria

Hello,I am new to Hibernate and i was trying to execute and() method in Hibernate Criteria Queries using Eclipse but the LogicalExpression will show error like
The method and(Criterion, Criterion) in the type Restrictions is not applicable for the arguments (Criteria, Criteria)
package actions;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.LogicalExpression;
import org.hibernate.criterion.Restrictions;
public class Andrestriction {
public static void main(String[] args) {
// TODO Auto-generated method stub
SessionFactory sf=new Configuration().configure().buildSessionFactory();
Session sn=sf.openSession();
Criteria cr=sn.createCriteria(PC.class);
Criteria id=(Criteria) Restrictions.gt("id",11);
Criteria os=(Criteria) Restrictions.ilike("os","d%");
LogicalExpression and=Restrictions.and(id,os); //This line will show error like this:-
//The method and(Criterion, Criterion) in the type Restrictions is not
//applicable for the arguments (Criteria, Criteria)
cr.add(and);
List l=cr.list();
Iterator itr=l.iterator();
while(itr.hasNext())
{
PC p=(PC)itr.next();
System.out.println(p.getId()+"\t"+p.getName()+"\t"+p.getOs());
}
sn.close();
}
}
I want to use and criteria in my Query.Please tell me how to Solve this problem.
Thanks in advance
Restrictions.gt() returns a SimpleExpression which is a Criterion (implements Criterion)
So you should not cast a SimpleExpression to a Criteria. You already have a criteria ( You create one criteria which actually transforms into a query and executed on database ), so what you need is:
Criteria cr=sn.createCriteria(PC.class);
Criterion id=Restrictions.gt("id",11); // No need to cast as SimpleExpression implements Criterion
Criterion os= Restrictions.ilike("os","d%");
LogicalExpression and=Restrictions.and(id,os);
cr.add(and);
A compiler error shows up because you are passing two Criteria objects to and() method of Restriction class but it expects Criterion objects. So change it as above and you are good to do.
As the error message indicates there is no matching Restrictions.and method with the given signature. When encountering these type-errors the first place that should be consulted is the documentation - then work back resolving the expected/actual types.
To fix this, drop the (invalid) cast and use the correct type for the variable;
// Criterion, not Criteria - also no cast
Criterion id = Restrictions.gt("id",11);
Criterion os = Restrictions.ilike("os","d%");
// Now it matches `and(Criterion, Criterion)`
LogicalExpression and = Restrictions.and(id, os);
Criteria (or criterions) are a collection of criterion; but modern English usage is a bit lax.

Categories

Resources