Is it possible to save a loaded class to a file?
Class cc = Class.forName("projects.implementation.JBean");
Or, maybe to get the physical location of that class?
Yes you can as Class.class implements Serializable interface you can serialize it into file and as well deserialize again.
Example -
Class Test{
public static void main(String[] args) throws ClassNotFoundException {
try {
OutputStream file = new FileOutputStream("test.ser");
OutputStream buffer = new BufferedOutputStream(file);
ObjectOutput output = new ObjectOutputStream(buffer);
try {
Class cc = Class.forName("com.test.Test");
System.out.println(cc);
output.writeObject(cc);
} finally {
output.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
try {
// use buffering
InputStream file = new FileInputStream("test.ser");
InputStream buffer = new BufferedInputStream(file);
ObjectInput input = new ObjectInputStream(buffer);
try {
// deserialize the class
Class cc = (Class) input
.readObject();
// display
System.out.println("Recovered Class: " + cc);
} finally {
input.close();
}
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Serializing a Class object in Java serializes little more than the qualified name of the class. When deserializing the class is looked up by name.
In the general case, I don't think it's possible to get the bytes corresponding to a class definition (the bytecode) once it has been loaded. Java permits classes to be defined at runtime and, so far as I'm aware, doesn't expose the bytes after the class has been loaded.
However, depending on the ClassLoader in use, you may find that
cc.getResourceAsStream("JBean.class")
is all you need, loading the class stream as a resource using its own ClassLoader.
Another option could be to intercept the loading of the class. The ClassLoader will get to see the bytes in "defineClass", so a custom ClassLoader could store them somewhere.
Related
i am new to java and i am learning deserialization and while doing so i am getting classcastexception
I did serialization at one class and deserialization at another
serialization
zipfile f = new zipfile(30,"kavin");
ArrayList<zipfile> a = new ArrayList<zipfile>(101);
a.add(f);
String file = "def.txt";
try {
FileOutputStream fi = new FileOutputStream(file);
ObjectOutputStream s = new ObjectOutputStream(fi);
s.writeObject(f);
System.out.println(f.age);
s.close();
fi.close();
} catch (FileNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
deserialization
String file = "def.txt";
try {
FileInputStream fi = new FileInputStream(file);
ObjectInputStream s = new ObjectInputStream(fi);
f=(deserialization)s.readObject();
System.out.println(f.age);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}
output
Exception in thread "main" java.lang.ClassCastException: demo2.zipfile cannot be cast to demo2.deserialization
at demo2.deserialization.main(deserialization.java:69)
The following must be kept in mind when dealing with Serialization:
If a parent class has implemented Serializable interface then child class doesn’t need to implement it but vice-versa is not true.
Only non-static data members are saved via Serialization process.
Static data members and transient data members are not saved via Serialization process. So, if you don’t want to save the value of a non-static data member then make it transient.
The constructor of the object is never called when an object is deserialized.
Associated objects must be implementing the Serializable interface.
Try to look thru your code and find if one of the above-mentioned cases is the problem.
For more help, refer to the source at - Serialization in Java
Idea
I have a jar (postgresql-9.4.1208.jre7.jar) in a byte[]. Id like to load and connect and run some basic SQL commands in runtime.
Implementation
Therefore I created a new Classloader:
public class JarClassloader extends ClassLoader {
public interface DriverProblemReporter {
void reportDriverProblem(String name, Throwable e);
}
private final byte[] driverdata;
private final DriverProblemReporter problemReporter;
public JarClassloader(byte[] jar, String drivername, DriverProblemReporter reporter) {
super(ClassLoader.getSystemClassLoader());
this.problemReporter = reporter;
try {
JarInputStream jis = new JarInputStream(new ByteArrayInputStream(jar));
JarEntry entry = jis.getNextJarEntry();
while (entry != null) {
handleEntry(entry, jis);
entry = jis.getNextJarEntry();
}
} catch (IOException e) {
e.printStackTrace();
}
this.driverdata = jar;
}
private void handleEntry(JarEntry entry, JarInputStream jis) {
if (!entry.isDirectory()) {
ByteArrayOutputStream baos;
try {
baos = new ByteArrayOutputStream();
IOUtils.copy(jis, baos);
baos.flush();
} catch (IOException e) {
problemReporter.reportDriverProblem(entry.getName(), e);
return;
}
try {
defineClass(baos.toByteArray(), 0, baos.size());
} catch (LinkageError e) {
problemReporter.reportDriverProblem(entry.getName(), e);
}
}
}
}
The Jar loads successfully and I am able to get a instance of the Driver.
Point of interrest
On the call to connect to a Database I get this Error:
java.lang.NoClassDefFoundError: org/postgresql/hostchooser/HostRequirement$1
at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:107)
at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:66)
at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:215)
at org.postgresql.Driver.makeConnection(Driver.java:406)
at org.postgresql.Driver.connect(Driver.java:274)
In the stacktrace I see the working instance of org.postgresql.Driver looking for a class named org/postgresql/hostchooser/HostRequirement$1.
Assumption
My JarClassloader does not load anonymous nested classes.
Question
What shall I do to successfully load all classes in the jar?
You need to load the classes in the order the classloader needs them, not in the order they happen to be in the JAR file. So you need to override the findClass() method and search the JAR file at that point for the class being requested.
It would be a lot simpler to use a file.
I am trying to read a text file, "text.txt", packaged at the root as a part of my jar file. in one case, my code calls class.getResourceAsStream("/test.txt") and in another case, my code calls class.getClassLoader().getResourceAsStream("/test.txt").
The first call gets the correct data but the second one doesn't get anything. any idea?
public static void main(String[] args) {
InputStream is = null;
try {
is = TestLoadResourcesByClass.class.getResourceAsStream("/test.txt");
StringWriter writer = new StringWriter();
IOUtils.copy(is, writer);
System.out.println(writer.toString());
} catch(Exception ex) {
ex.printStackTrace();
} finally {
if(null != is) { try { is.close(); } catch(Exception ex) { } }
}
}
public static void main(String[] args) {
InputStream is = null;
try {
is = TestLoadResourcesByClassLoader.class.getClassLoader().getResourceAsStream("/test.txt");
StringWriter writer = new StringWriter();
IOUtils.copy(is, writer);
System.out.println(writer.toString());
} catch(Exception ex) {
ex.printStackTrace();
} finally {
if(null != is) { try { is.close(); } catch(Exception ex) { }
}
}
let's say i have 2 jar files
first.jar : contains TestLoadResourcesByClass.class (code to read test.txt)
second.jar : contains "test.txt" at the root
and then i run my code as follows
java -cp first.jar;second.jar;commons-io-2.4.jar test.TestLoadByClass
i also get no output at the console. is that because the classes/resources in second.jar have not been loaded? in fact, i get a null pointer exception (input stream is null).
any idea on what's going on?
It is explained in the javadoc for Class.getResourceAsStream. That method removes the / from the start of resource names to create the absolute resource name that it gives to ClassLoader.getResourceAsStream. If you want to call ClassLoader.getResourceAsStream directly then you should omit the / at the start.
I'm working on a school assignment that is supposed to open a serialized file and output it. I can't figure out why it isn't printing anything. It doesn't seem like the loop is working at all. Any ideas?
public ReadFile()
{
try
{
fis = new FileInputStream("Clients.ser");
ois = new ObjectInputStream(fis);
}
catch(Exception e) {}
try
{
while(true)
{
//cast according to class Record
r = (Record) ois.readObject();
System.out.print(r.account + r.firstName + r.lastName + r.balance);
}
}
catch(IOException ioe) { ioe.printStackTrace(); }
catch(ClassNotFoundException cnfe) {}
}
Edit
Added a stacktrace to IOException and it returned:
Record; local class incompatible: stream classdesc serialVersionUID = 5124020354301486787, local class serialVersionUID = -8881068308941519505
ReadFile.java
Record.java
That message means that the class you are trying to deserialize is not the same as the class you specified.
Were you given the Record class by whoever serialized it, or did you write it yourself?
I know we can load a Object from .class file and my question is how to do it reversely.
I use Class.forName("classname") to get a Class object and how can I write this back to the .class file?
Serialization class is not the point for this issue because the loaded file may not be implement Serializable interface.
The reason why I ask this is I need convert Class object to java source text string. If anyone knows how to convert Object class to source directly, it might be great helpful.
If you want to add functions etc to a class you can use.
http://www.jboss.org/javassist
example:
clazz = fullclass name, method = "public void doxxx(){ int x =0;x++}"
private static void createMethod(String clazz,String method){
ClassPool pool = ClassPool.getDefault();
try {
Class<?> class1 = Class.forName(clazz);
class1.getProtectionDomain().getCodeSource().getLocation();
pool.insertClassPath(new ClassClassPath(class1));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
CtClass pt;
try {
pt = pool.get(clazz);
CtMethod m = CtNewMethod.make(method, pt);
pt.addMethod(m);
pt.writeFile();
pt.toClass();
} catch (NotFoundException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}