I need to create some classes (which will be mostly used as DTO and
DAO) and I used ASM
The thing is that then I cannot do such things as:(this is pseudo
code I have tried many different things to no avail):
Class K = _.getKlass();
K0 Obj = (K0)K.newInstance
ArrayList<K0> ALK0 = new ArrayList<K0>();
ALK0.add(Obj);
Even though I know he name of the class is that I created saved and
loaded in the same context using the URLClassLoader is "K0"
I know the created classes themselves are fine because the JVM (javap
and java) did not complain at all and I actually used the classes by
starting other JVM and reaching out for them
Again I need to use the created classes to create and used typed
objects right within the same context that they were created, without
having to restart java
How could you achieve such a thing, either in a plain way or hacking
my way through?
In case this can not be done (well, this may be why some frameworks
such as JAXB use precompilation of type classes), please let me know
what am I missing here
Thanks
lbrtchx
Here is a short code sample of what I am trying to achieve:
// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
import java.util.*;
import java.io.*;
import java.net.*;
import java.security.*;
import org.objectweb.asm.*;
import static org.objectweb.asm.Opcodes.*;
// __
class ASMKW02 extends ClassLoader{
private File FlDir;
private String aKName;
private String[][] aFldDefs;
// __ more sanity checks
ASMKW02(File FlDir, String aKName, String[][] aFldDefs){
if(!FlDir.exists()){ FlDir.mkdirs(); }
this.FlDir = FlDir;
this.aKName = aKName;
this.aFldDefs = aFldDefs;
}
// __
public Class getK(){
Class K = null;
// __
ClassWriter KW = new ClassWriter(ClassWriter.COMPUTE_MAXS);
// __ class def.
KW.visit(V1_6, ACC_PUBLIC, aKName, null, "java/lang/Object", null);
// __ default constructor
MethodVisitor DfltCtor = KW.visitMethod(ACC_PUBLIC, "<init>", "()V",
null, null);
if(DfltCtor != null) {
DfltCtor.visitCode();
DfltCtor.visitVarInsn(ALOAD, 0);
DfltCtor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object",
"<init>", "()V");
DfltCtor.visitInsn(RETURN);
DfltCtor.visitMaxs(1, 1);
DfltCtor.visitEnd();
}
// __ K Fields
FieldVisitor FV;
for(int i = 0; (i < aFldDefs.length); ++i){
FV = KW.visitField(ACC_PUBLIC, aFldDefs[i][0], aFldDefs[i][1],
null, null);
if(FV != null){ FV.visitEnd(); }
else{} // . . .
}
// __
KW.visitEnd();
// __
byte[] bKAr = KW.toByteArray();
// __ Checking if class has been already loaded by JVM . . .
File Fl = new File(FlDir, aKName + ".class");
try{
ClassLoader KLCtxt =
Thread.currentThread().getContextClassLoader();
URL U = (Fl.toURI()).toURL();
URLClassLoader UKL = new URLClassLoader(new URL[]{U}, KLCtxt);
try{ K = Class.forName(aKName, true, UKL); }
catch(ClassNotFoundException KNFX)
{ KNFX.printStackTrace(System.err); }
if(K == null){
// __
K = defineClass(aKName, bKAr, 0, bKAr.length);
if(K != null){
System.out.println("// __ Class K: |" + K + "|");
try{
FileOutputStream FOS = new FileOutputStream(Fl);
FOS.write(bKAr);
FOS.close();
}catch(FileNotFoundException FNFX)
{ FNFX.printStackTrace(System.err); }
catch(IOException IOX){ IOX.printStackTrace(System.err); }
}
}
}catch(MalformedURLException MFX)
{ MFX.printStackTrace(System.err); }
// __
return(K);
}
}
// __
public class ASMKW02Test{
public static void main(String[] aArgs){
// __
String aKLoadDir = "/media/sda2/prjx/java/Ks";
File FlDir = new File(aKLoadDir);
// __ K Name
String aKName = "KNm00";
// __ K Fields
String[][] aFldDefs = new String[][]{
{"bByte", "B"}, // byte
{"cChar", "C"}, // char
{"dDouble", "D"}, // double
{"fFloat", "F"}, // float
{"iInt", "I"}, // int
{"lLong", "J"}, // long
{"sShort", "S"}, // short
{"Is", "Z"}, // boolean
{"aNm", "Ljava/lang/String;"},
{"ALS", "Ljava/util/ArrayList<String>;"},
{"HMSI", "Ljava/util/Hasmap<String, Integer>;"}
};
// __
ASMKW02 ASMK = new ASMKW02(FlDir, aKName, aFldDefs);
Class K = ASMK.getK();
System.out.println("// __ Class K: |" + K + "|");
try{
K.newInstance();
}catch(InstantiationException InstX)
{ InstX.printStackTrace(System.err); }
catch(IllegalAccessException IlglAxX)
{ IlglAxX.printStackTrace(System.err); }
}
}
// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
If I've read you right, the type K0 is created at runtime.
> ArrayList<K0> ALK0 = new ArrayList<K0>();
> ALK0.add(Obj);
Generics are checked at compile time, well before K0 ever exists.
If your generated DAOs implement a known interface that exists at
compile time, then you can cast them to that and create a generic list
whose type parameter is that interface, but you can't use generics
with the actual type of a class created at runtime.
-o
Yes, it is
>> ArrayList<K0> ALK0 = new ArrayList<K0>();
>> ALK0.add(Obj);
>Generics are checked at compile time, well before K0 ever exists.
Well, this is what I know ;-), but I wanted to somehow find out about
some magic trick that would let me get the structure to describe some
entity from which I will only know at run time and then operate on it
>If your generated DAOs implement a known interface that exists at
>compile time, then you can cast them to that and create a generic list
>whose type parameter is that interface, but you can't use generics
>with the actual type of a class created at runtime.
I will look into using a registry of interfaces then
lbrtchx
how does JASPER recompile a JSP, which is ultimately a sevlet/java
class file, and updates itself when you, say include new classes to be
used by a JSP?
What happens when these classes include generics?
Tomcat's main process doesn't have to be restarted, so something must
be happening there for jasper/the servlet engine to load these new
classes
lbrtchx
The servlet engine calls the JSP compiler if it thinks the JSP source needs
retranslation. The engine polls the JSP source for changes periodically.
> class file, and updates itself when you, say include new classes to be
> used by a JSP?
If you change a web application, you'd redeploy the WAR through the servlet
container, which would unpack all the classes and do whatever else it does
when it redeploys an application.
> What happens when these classes include generics?
WARs deploy only bytecode, in which generics have already been erased.
--
Lew
You can reload a class by using a new classloader (and let the
old classloader and all objects of classes loaded by it go to GC).
Arne
package test.k00;
public class K00{
public int i0;
public long l0;
}
package test.k00;
public class K02{
public int i2;
public String aS2;
}
package test.k00;
import java.util.*;
// __
public class GenK00<T>{
private String aS;
public ArrayList<T> ALK00 = new ArrayList<T>();
// __
public GenK00(String aS){
this.aS = aS;
}
}
~
4) Inside of index.jsp I included:
<p>
Loading Generic classes:<br/>
<%@page import="test.k00.*"%>
<%
GenK00<String> GK0 = new GenK00<String>("<String>");
GK0.ALK00.add("blue");
GK0.ALK00.add("rote");
GK0.ALK00.add("blanco");
K00 k0 = new K00();
k0.i0 = 0;
k0.l0 = 0L;
K00 k1 = new K00();
k1.i0 = 1;
k1.l0 = 1L;
K00 k2 = new K00();
k2.i0 = 2;
k2.l0 = 2L;
GenK00<K00> GK2 = new GenK00<K00>("K00");
GK2.ALK00.add(k0);
GK2.ALK00.add(k1);
GK2.ALK00.add(k2);
GK2.ALK00.add(k1);
K02 J = new K02();
J.i2 = 4748;
J.aS2 = "aS2";
%>
<br/>
GK0.ALK00.size(): <%=GK0.ALK00.size()%>
<br/>
GK0.ALK00: <%=GK0.ALK00%>
<br/>
GK2.ALK00.size(): <%=GK2.ALK00.size()%>
<br/>
GK2.ALK00: <%=GK2.ALK00%>
<br/>
J: <%=J%>
</p>
So all that I needs to be done is look into tc classloaders
Am I missing anything here?
lbrtchx