Serialization issue with SortedSet, Arrays, an Serializable - java

I have this before the process:
protected void onPostExecute(SortedSet<RatedMessage> result) {
List<Object> list=Arrays.asList(result.toArray());
lancon.putExtra("results", list.toArray()); // as serializable
}
then in the other part I have
Object o=this.getIntent().getSerializableExtra("results");
//at this point the o holds the correct value (checked by debugger)
RatedMessage[] rm = (RatedMessage[]) o;// this line hangs out w ClassCastException
resultSet = new TreeSet<RatedMessage>(new Comp());
Collections.addAll(resultSet, rm);
Why I get the ClassCastException?

Finally I got it to work this way:
Serializable s = this.getIntent().getSerializableExtra("results");
Object[] o = (Object[]) s;
if (o != null) {
resultSet = new TreeSet<RatedMessage>(new Comp());
for (int i = 0; i < o.length; i++) {
if (o[i] instanceof RatedMessage) {
resultSet.add((RatedMessage) o[i]);
}
}
}

I'm sorry; I overlooked the use of the no-arg toArray() call.
Please note that there's overloaded toArray(T[]) method that takes an array as an argument.
By using this form, you can control the component type of the array, and it will work as expected.
protected void onPostExecute(SortedSet<RatedMessage> result) {
lancon.putExtra("results", result.toArray(new RatedMessage[result.size()]));
}

Related

java reflection for generic type when using jdbc

In C#, I got an utility that cast Datatable into a list of specified model, like this:
Datatable dt = conn.GetDataTable();
List<BookModel> result = EntityHelper<BookModel>.GetListModel(dataTable);
And the GetListModel() method that using generic type goes like this:
public static List<T> GetListModel(DataTable dt)
{
List<T> lObject= new List<T>();
for (int i = 0; i < dt.Rows.Count; i++)
{
T obj = new T();
for (int j = 0; j < dt.Columns.Count; j++)
{
int index = IndexOfField( dt.Columns[j].ColumnName );
if (index != -1)
{
PropertyInfo pi = obj.GetType().GetProperties()[index];
Type propType = pi.PropertyType;
if (propType.IsGenericType && (propType.GetGenericTypeDefinition() == typeof( Nullable<> )))
{
propType = propType.GetGenericArguments()[0];
}
if (propType.IsEnum)
{
int objectValue = 0;
Int32.TryParse( dt.Rows[i][j].ToString(), out objectValue );
pi.SetValue( obj, Enum.ToObject( propType, objectValue ), null );
}
else if (dt.Columns[j].DataType == propType && dt.Rows[i][j] != DBNull.Value)
{
pi.SetValue( obj, dt.Rows[i][j], null );
}
else if ((propType.Name.Equals( "Boolean" ) || propType.Name.Equals( "bool" )) && dt.Rows[i][j] != DBNull.Value)
{
pi.SetValue( obj, Convert.ToBoolean( dt.Rows[i][j] ), null );
}
}
}
lObject.Add( obj );
}
return lObject;
}
That is C# story, now back to Java. I'm using JDBC to execute a stored proc and return a ResultSet. But I found that in Java, generic type got its information erased at the runtime so I cannot do something like this:
public static <T> List<T> castObject(ResultSet rs)
{
T x = new T(); //IMPOSSIBLE ;___;
Field[] fields = x.getClass().getDeclaredFields();
for(Field field: fields)
{
field.setAccessible(true);
}
....
}
If it's impossible to create an utility like this, then is there anyway to reduce boilerplate code after getting a resulset ? My table got like 30 columns and I do not want to deal with codes like this:
actor.setFirstName(rs.getString("first_name"));
actor.setLastName(rs.getString("last_name"));
...
You can instantiate the class by passing a Class instance as a parameter to your method. How you do so depends on the version of Java you are using, but here is an example of Java 9 and later (though earlier versions are similar):
public static <T> List<T> castObject(ResultSet rs, Class<T> clazz) throws NoSuchMethodException,
IllegalAccessException, InvocationTargetException, InstantiationException {
Constructor<T> constructor = clazz.getConstructor();
T t = constructor.newInstance();
...
}
To call the method:
List<BookModel> bookModels = castObject(rs, BookModel.class);
Calls to setAccessible can be problematic though. This discussion shows a workaround. How to solve InaccessibleObjectException ("Unable to make {member} accessible: module {A} does not 'opens {package}' to {B}") on Java 9?

What is "Type mismatch" and how do I fix it?

How to fix this error?
Type mismatch: cannot convert from element type Object to Block
I see it at this line:
for (Block b : blocksToSkip){
Here is the full code.
#EventHandler(priority=EventPriority.NORMAL, ignoreCancelled=true)
public void onEntityExplode(EntityExplodeEvent ev){
ArrayList blocksToSkip = new ArrayList();
Location rootLoc = ev.getLocation();
if (!SkyMagic.IsInIslandWorld(rootLoc)) return;
for (Block b : ev.blockList()){
Location loc = b.getLocation();
IslandData data = SkyMagic.GetIslandAt(loc);
if ((data != null) && (data.owner != null)){
blocksToSkip.add(b);
}
}
for (Block b : blocksToSkip){
ev.blockList().remove(b);
}
}
This is a raw type:
ArrayList blocksToSkip
Java expects everything, not only the Block type.
Therefore, you need a type cast.
ArrayList blocksToSkip = new ArrayList();
// Rest of your code
for (Object b : blocksToSkip){
ev.blockList().remove( (Block)b );
}
Note it is discouraged to use raw types.
You should parameterize instead.
ArrayList<Block> blocksToSkip = new ArrayList<Block>();

Using references like pointers in method call in Java

I encountered a problem while dealing with a call of a static method in another class.
So I have a function which is like follow, where I need to extract two values, a counter and an object :
public static int getEarliestValue(Map<DBObject, DBCursor> cursorMap, DBObject result) {
int mergeCount = 1;
if (!cursorMap.isEmpty()) {
long ealiest = Long.MAX_VALUE;
for (DBObject o : cursorMap.keySet()) {
// do stuff to init tmp
...
if (tmp < ealiest) {
result = o;
ealiest = tmp;
}
// other stuff .....
}
return mergeCount;
}
here is how I call it in my other class :
DBObject result= null;
int mergeCount = MongoTickReaderUtil.getEarliestValue(cursorList, result);
I checked in debug mod and result is set in getEarliestValue but when it's go out of the function call result is still null.
I thought that references where like pointers with the difference that we couldn't do arithmetic operation on the reference itself, but with this behavior it seems that even if we change the pointed value it still only in the local scope.
The only idea that I found was to put it in a List but this is neither elegant nor optimal.
Any suggestion ? Thanks in advance.
Passing result here is the same thing as passing null. You have to return this DBObject someway. For example, you can return something like Map.Entry<Integer, DBObject>. This could not be supposed to be a good solution, maybe you should create some class like BlahBlahResult, containing both int result and DBObject.
If you really-really want to pass it as a parameter, you may pass something like AtomicReference<DBObject> and set it inside the method:
public static int getEarliestValue(Map<DBObject, DBCursor> cursorMap, AtomicReference<DBObject> result) {
int mergeCount = 1;
if (!cursorMap.isEmpty()) {
long ealiest = Long.MAX_VALUE;
for (DBObject o : cursorMap.keySet()) {
// do stuff to init tmp
...
if (tmp < ealiest) {
result.set(o);
ealiest = tmp;
}
// other stuff .....
}
return mergeCount;
}
...
...
AtomicReference<DBObject> resultReference = new AtomicReference<>(null);
int mergeCount = MongoTickReaderUtil.getEarliestValue(cursorList, resultReference);
DBObject result = resultReference.get();
In java "References to Objects are passed by value".
DBObject result= null;
int mergeCount = MongoTickReaderUtil.getEarliestValue(cursorList, result); // here result --> null i.e, points to nothing
public static int getEarliestValue(Map<DBObject, DBCursor> cursorMap, DBObject result) {
int mergeCount = 1;
if (!cursorMap.isEmpty()) {
long ealiest = Long.MAX_VALUE;
for (DBObject o : cursorMap.keySet()) {
// do stuff to init tmp
...
if (tmp < ealiest) {
result = o; // here (new)result --> o . (original)result-->null
ealiest = tmp;
}
// other stuff .....
}
return mergeCount;
}
the result parameter is a pointer. Java does not support pointer-to-pointer as in c/c++.
you can use a class contains a DBObject field, then pass this class to the method.
class Dummy {
DBObject result;
}
modify your getEarliestValue method, replace the argument DBObject result with Dummy dummy,
public static int getEarliestValue(Map<DBObject, DBCursor> cursorMap, Dummy dummy)
and then replace code result = o with dummy.result = o
Dummy dummy = new Dummy();
int mergeCount = MongoTickReaderUtil.getEarliestValue(cursorList, dummy);
DBObject result = dummy.result;
this is a simulation of **ptr in c/c++
You can do the following:
DBObject result= new DBOBject() // or any initializing code;
/** don't try to change or re-initialize reference inside the method
because the result will still point to old one
*/
int mergeCount = MongoTickReaderUtil.getEarliestValue(cursorList, result);
// use the result reference.
This is not specific for java also in the C++ or C pointer unless you use the & with pointer reference.
Note that it seems that the method cann't run alone with out DBObject instance so I think this method should be an instance method of Class DBObject and not a Util method,
For example:
int mergeCount = result.getEarliestValue(cursorList);

Creating a object from java reflection without knowing the constructor parameters

I am trying to create a collecion of objects using reflection. I have the class name. But at compile time have no idea about the constructor. I used this tutorial.
import java.lang.reflect.*;
public class constructor2 {
public constructor2()
{
}
public constructor2(int a, int b)
{
System.out.println(
"a = " + a + " b = " + b);
}
public static void main(String args[])
{
try {
Class cls = Class.forName("constructor2");
Class partypes[] = new Class[2];
partypes[0] = Integer.TYPE;
partypes[1] = Integer.TYPE;
Constructor ct
= cls.getConstructor(partypes);
Object arglist[] = new Object[2];
arglist[0] = new Integer(37);
arglist[1] = new Integer(47);
Object retobj = ct.newInstance(arglist);
}
catch (Throwable e) {
System.err.println(e);
}
}
}
Now let's say I don't know abut the parameters of the constructors. (Whether it's a default constructor or two integers). The costructor parameters can change from class to class. I have no idea about the Constructor2 class. But I have the className.
So I cant create the "argList" as above. Any idea how I can create a object from constructors then.
I did as follows
Constructor[] brickConstructorsArray = brickClass.getConstructors();
for (Constructor constructor : brickConstructorsArray) {
Class[] constructorParams = constructor.getParameterTypes();
Object argList[] = new Object[constructorParams.length];
int index = 0;
for (Class cls : constructorParams) {
if (cls.equals(Sprite.class)) {
Object spriteOb = foundSprite;
argList[index] = spriteOb;
} else if (cls.equals(double.class)) {
Object dblObj = new Double(0.0);
argList[index] = dblObj;
}
index++;
}
brickObject = (Brick) constructor.newInstance(argList);
}
This would work for costrcutors which will have Sprite or double parameters. To include other possibilities I'd have to create a loooong if else chain. Need help.
Do you really not care what values you're going to pass? You could have a map from each primitive class to a default value of its wrapper type:
// You can make this a static member somewhere
Map<Class<?>, Object> primitiveValues = new HashMap<Class<?>, Object>();
primitiveValues.put(char.class, '\0');
// etc
... and just use null for any non-primitive type. So:
Constructor[] brickConstructorsArray = brickClass.getConstructors();
for (Constructor constructor : brickConstructorsArray) {
Class[] constructorParams = constructor.getParameterTypes();
Object argList[] = new Object[constructorParams.length];
// When you need the index, there's no point in using the enhanced
// for loop.
for (int i = 0; i < constructorParams.length; i++) {
// Fetching the value for any non-primitive type will
// give null, which is what we were going to use anyway.
argList[i] = primitiveValues.get(constructorParams[i]);
}
brickObject = (Brick) constructor.newInstance(argList);
}
Of course I'd expect this to fail quite often. After all, if you don't know anything about the constructor you're calling, you have no idea what arguments are going to be valid.
Is this really something you're expecting to find useful?

reflection static method argument string

public class Star{
public static ArrayList initdata(String pattern) {
ArrayList data = new ArrayList();
if (pattern != "") {
ModelCollection mc = Star.find(pattern, 0);
Iterator dataIterator = mc.iterator();
while (dataIterator.hasNext()) {
Star star = (Star) dataIterator.next();
data.add(star.getName());
Debug.trace("StarName" + star.getName());
}
}
Collections.sort(data);
return data;
}
}
I want to invoke method initdata using reflection, I tried to write something like this , but it does not work:
Class c = Class.forName("com.cubiware.fyretv.application.model.Star");
par[0] = String.class;
Method mthd = c.getMethod("initdata", par);
ArrayList output = (ArrayList) mthd.invoke(null, null);
try
ArrayList output = (ArrayList) mthd.invoke(null, (String)null);
It's not good idea to pass null, when method expects Object...
May be this will help
Calling Java varargs method with single null argument?
First, Your check seems weird to me: try if (pattern != null) instead of if (pattern != "").
Why don't you pass the par array, you have illegal argument exception I think. try passing arguments array.
Object[] args = {"someString / maybe null"};
ArrayList output = (ArrayList) mthd.invoke(null, args);
Obviously, your invoke call is similiar to
initdata(null);
Now, inside initdata you do not filter the case where pattern == null which leads us to a call
Star.find(null, 0);
We do not know the implementation of this method - if we're lucky, we get an empty collection. Otherwise, I expect a NullPointerException either in Star.find or later at mc.iterator()
$ javac -cp dp4j-1.2-SNAPSHOT-jar-with-dependencies.jar -Averbose -All Star.java
Star.java:12:
import com.dp4j.*;
public class Star {
public Star() {
super();
}
public static ArrayList initdata(String pattern) {
return null;
}
#Reflect()
public static void main(String[] args) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.NoSuchMethodException, java.lang.reflect.InvocationTargetException, java.lang.IllegalArgumentException {
final java.lang.reflect.Method initdataWithStringMethod = Class.forName("Star").getDeclaredMethod("initdata", .java.lang.String.class);
initdataWithStringMethod.setAccessible(true);
initdataWithStringMethod.invoke("", new .java.lang.Object[1][]{null});
final java.lang.reflect.Method printlnWithStringMethod = Class.forName("java.io.PrintStream").getDeclaredMethod("println", .java.lang.String.class);
printlnWithStringMethod.setAccessible(true);
printlnWithStringMethod.invoke(System.out, new .java.lang.Object[1][]{"Varargs + reflection? No problem"});
}
}
public static void main(String args[]) {
^
$ java Star
Varargs + reflection? No problem

Categories