I have situation where my Java class needs to create a ton of certain kind of objects. I would like to give the name of the class of the objects that are created as a parameter. In addition, I need to give the created class a parameter in its constructor. I have something like
class Compressor {
Class ccos;
public Compressor(Class ccos) {
this.ccos = ccos;
}
public int getCompressedSize(byte[] array) {
OutputStream os = new ByteArrayOutputStream();
// the following doesn't work because ccos would need os as its constructor's parameter
OutputStream cos = (OutputStream) ccos.newInstance();
// ..
}
}
Do you have any ideas how I could remedy this?
Edit:
This is part of a research project where we need to evaluate the performance of multiple different compressors with multiple different inputs. Class ccos is a compressed OutputStream either from Java's standard library, Apache Compress Commons or lzma-java.
Currently I have the following which appears to work fine. Other ideas are welcome.
OutputStream os = new ByteArrayOutputStream();
OutputStream compressedOut = (OutputStream) ccos.getConstructor(OutputStream.class).newInstance(os);
final InputStream sourceIn = new ByteArrayInputStream(array);
You can use the Class.getConstructor(paramsTypes...) method and call newInstance(..) on the constructor. In your case:
Compressor.class.getConstructor(Class.class).newInstance(Some.class);
Using Spring ClassUtils and BeanUtils classes you can avoid dealing with those tedious exceptions that is Spring handling for you :
Constructor<Car> constructor = ClassUtils.getConstructorIfAvailable(Wheels.class, Etc.class);
Car car = BeanUtils.instantiateClass(constructor, new Wheels(), new Etc());
You have to get to the relevant Constructor object (e.g. via Class.getConstructors or Class.getConstructor) and then call constructor.newInstance, giving it the arguments it requires.
An example you can use is as follows:
lets say conn is a connection to the database.
Class[] btarray = { conn.getClass() };
try {
if (classname != null) {
pmap = (Mapper) Class.forName(classname)
.getConstructor(btarray)
.newInstance(
new Object[] { conn }
);
}
} catch (Throwable x) {
x.printStackTrace(Log.out);
}
btarray allows you to pass in arguments to the constructor.
class Compresor<T> {
private Class<? extends T> clazz;
Compresor(final Class<? extends T> cls){
this.clazz = cls
}
}
Related
I have a gradle project with two modules, library and app. library is a java-library that can be published as maven artifact. It contains some util methods that are used by app, hence app depends on library.
Now, I'd like to add two util methods for serialization as shown below. Depending on where the util methods are placed and whether or not the serialized string of MyClass (which is also located in app) is written to a csv file in between (serialize -> export -> import -> deserialize).
Case 1 / No Problem: As long as my util methods are part of app, I can serialize and deserialize MyClass without any problems, even if I export the serialized string to a csv-file in between.
Case 2 / No Problem: When my utils methods are part of library, I can only serialize and deserialize MyClass, if the serialized string is not written to a csv-file in between.
Case 3 / PROBLEM: If my utils are placed in library and the serialized string is written to a csv-file in between, then I get a java.lang.ClassCastException: Cannot cast my.package.MyClass to my.package.MyClass at java.base/java.lang.Class.cast(Class.java:3605).
When I run the debugger up until ois.readObject(), I can even see the properly deserialized object. However, it is not possible to cast it correctly.
Could anyone help me to find the reason for the situation described above? Any ideas why this error could occur? Any ideas why it might not be allowed to have my util methods in library?
#Nonnull
public static <T> String serialize(T object) throws IllegalStateException {
try (
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
final ObjectOutputStream oos = new ObjectOutputStream(bos)
) {
oos.writeObject(object);
return Base64.getEncoder().encodeToString(bos.toByteArray());
} catch (final IOException e) {
throw new IllegalStateException("serialization failed", e);
}
}
#Nonnull
public static <T> T deserialize(String objectAsString, Class<T> tClass) throws IllegalStateException {
final byte[] data = Base64.getDecoder().decode(objectAsString);
try (
final ByteArrayInputStream bis = new ByteArrayInputStream(data);
final ObjectInputStream ois = new ObjectInputStream(bis)
) {
return tClass.cast(ois.readObject());
} catch (Exception e) {
throw new IllegalStateException("deserialization failed", e);
}
}
I have got an OutputStream which can be initialized as a chain of OutputStreams. There could be any level of chaining .Only thing guaranteed is that at the end of the chain is a FileOutputStream.
I need to recreate this chained outputStream with a modified Filename in FileOutputStream. This would have been possible if out variable (which stores the underlying chained outputStream) was accessible ; as shown below.
public OutputStream recreateChainedOutputStream(OutputStream os) throws IOException {
if(os instanceof FileOutputStream) {
return new FileOutputStream("somemodified.filename");
} else if (os instanceof FilterOutputStream) {
return recreateChainedOutputStream(os.out);
}
}
Is there any other way of achieving the same?
You can use reflection to access the os.out field of the FilterOutputStream, this has however some drawbacks:
If the other OutputStream is also a kind of RolloverOutputStream, you can have a hard time reconstructing it,
If the other OutputStream has custom settings, like GZip compression parameter, you cannot reliable read this
If there is a
A quick and dirty implementation of recreateChainedOutputStream( might be:
private final static Field out;
{
try {
out = FilterInputStream.class.getField("out");
out.setAccessible(true);
} catch(Exception e) {
throw new RuntimeException(e);
}
}
public OutputStream recreateChainedOutputStream(OutputStream out) throws IOException {
if (out instanceof FilterOutputStream) {
Class<?> c = ou.getClass();
COnstructor<?> con = c.getConstructor(OutputStream.class);
return con.invoke(this.out.get(out));
} else {
// Other output streams...
}
}
While this may be ok in your current application, this is a big no-no in the production world because the large amount of different kind of OutputStreams your application may recieve.
A better way to solve would be a kind of Function<String, OutputStream> that works as a factory to create OutputStreams for the named file. This way the external api keeps its control over the OutputStreams while your api can adress multiple file names. An example of this would be:
public class MyApi {
private final Function<String, OutputStream> fileProvider;
private OutputStream current;
public MyApi (Function<String, OutputStream> fileProvider, String defaultFile) {
this.fileProvider = fileProvider;
selectNewOutputFile(defaultFile);
}
public void selectNewOutputFile(String name) {
OutputStream current = this.current;
this.current = fileProvider.apply(name);
if(current != null) current.close();
}
}
This can then be used in other applications as:
MyApi api = new MyApi(name->new FileOutputStream(name));
For simple FileOutputStreams, or be used as:
MyApi api = new MyApi(name->
new GZIPOutputStream(
new CipherOutputStream(
new CheckedOutputStream(
new FileOutputStream(name),
new CRC32()),
chipper),
1024,
true)
);
For a file stream that stored checksummed using new CRC32(), chipped using chipper, gzip according to a 1024 buffer with sync write mode.
I'm calling an api to get the an input stream and then call static method parseFrom(inputstream) to convert it to the protobuffclass.
If I do it with a specific class it works:
public CustomerDTOOuterClass.CustomerDTO GetCustomer()
{
CustomerDTOOuterClass.CustomerDTO customer = null;
try
{
URL url = new URL("https://localhost:44302/Api/customer/1?");
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Content-Type", "application/x-protobuf");
conn.connect();
InputStream is = conn.getInputStream();
CustomerDTOOuterClass.CustomerDTO customer =
CustomerDTOOuterClass.CustomerDTO.parseFrom(is);
conn.disconnect();
}
catch(Exception ex)
{
System.out.println("[ "+ex.getMessage()+" ]");
}
return customer;
}
but if I change it to generic type it fails because T doesn't have the method parseFrom, is there any interface I could implement in T so I can call the parseFrom method?
public T GetObject()
{
T object = null;
try
{
URL url = new URL("https://localhost:44302/Api/customer/1?");
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Content-Type", "application/x-protobuf");
conn.connect();
InputStream is = conn.getInputStream();
T object = T.parseFrom(is);
conn.disconnect();
}
catch(Exception ex)
{
System.out.println("[ "+ex.getMessage()+" ]");
}
return object;
}
this is the error I get:
Error:(68, 27) error: cannot find symbol method parseFrom(InputStream)
Every generated protobuf type contains a static member called PARSER which is an implementation of the com.google.protobuf.Parser<T> interface. Your getObject method simply needs to take a Parser<T> as a parameter. So then you'd call it like:
Foo foo = getObject(Foo.PARSER);
If you want to do this for T, it's easier and more natural to pass the Class<T> (i.e. the class of the Proto type) into the constructor of your class, and then obtain the Parser from that like this:
public class Thing<T extends Message> {
final Parser<T> parser;
Thing(Class<T> cls) {
parser = (Parser<T>) cls.getMethod("parser").invoke(null);
}
T deserialize(byte[] bytes) {
parser.parseFrom(bytes); // try/catch etc
}
}
To expand on Kenton Varda's answer:
First I'd refactor your method into separate methods for getting the input stream and parsing it. Only the latter has any reason to be generic.
public InputStream getInputStream() {
// get it
}
Now you intend to parse the input stream and build a POJO from the protobuf. It's reasonable IMO to expect that at this point your code must be aware of what type of object you're going to get, because otherwise how would you do something intelligent with it next? E.g.
InputStream is = getInputStream();
Object o = parseGenericInputStream(is);
doSomethingWithParsedObject(o); // how to do this if you don't know o's type?
You reasonably must know o's type once you've parsed it (and therefore before you parse it), otherwise you can't do anything meaningful with it that I can think of.
So... again with credit to Kenton Varda:
public void doStuff() {
...
InputStream is = getInputStream();
MyProtobufClass pojo = parseGenericInputStream(MyProtobufClass.PARSER, is);
doSomethingWithParsedObject(pojo);
...
}
private <T> T parseGenericInputStream(Parser<T> parser, InputStream inputStream)
throws InvalidProtocolBufferException {
return parser.parseFrom(inputStream);
}
At this point though you're writing a generic method for one line of code, which is kind of not worth it if you ask me.
No, there is not; you cannot deserialize a proto without knowing its type.
If you do know its type, then you can pass in a Builder for its type, however.
(Additionally, you can't call static methods on a type variable like T.)
I'm really newbie to groovy scripting but following some tutorial I tried to dynamically load some groovy class within my java code using parseClass() method of GroovyClassLoader.
I wrote some snippet and it worked fine for me. The problem is that I don't clearly understand what groovy engine is doing beyond my view and how those scripts are compiled?
Does a new class gets creted and loaded into jvm? Or does my application uses some cached sources?
Here is the class I'm trying to parse:
private static class MyScript {
#Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("public class SomeClass\n");
builder.append("{\n");
builder.append("Some code...").append("\n");
builder.append("}\n");
return builder.toString();
}
The I load it with build() as below:
private Class MyGroovyBuilder {
private Script script = new Script();
public String build() throws TemplateCompilationException
//
String groovyText = script.toString();
//
CompilerConfiguration config = new CompilerConfiguration();
//
byte[] bytes;
try
{
bytes = groovyText.getBytes(config.getSourceEncoding());
}
catch (UnsupportedEncodingException e)
{
throw new TemplateCompilationException(e, groovyText);
}
//
InputStream in = new ByteArrayInputStream(bytes);
GroovyCodeSource gcs = new GroovyCodeSource(in, "SomeName", "/groovy/shell");
GroovyClassLoader loader = new
GroovyClassLoader(Thread.currentThread().getContextClassLoader(), config);
Class<?> scriptClass;
try
{
scriptClass = loader.parseClass(gcs, false);
}
catch (CompilationFailedException e)
{
throw new GroovyCompilationException(e, "SomeName", groovyText);
}
catch (ClassFormatError e)
{
throw new GroovyCompilationException(e, "SomeName", groovyText);
}
return scriptClass.getName();
}
Any clarification is greatelly appreciated.
BR.
After loading class it appears in your class loader, and can be accessed like any other class.
There is a simple tutorial [here], that show how to load class from string.
In simplest case, you can load class, and hold it's Class object, using it to create objects dynamically. For field access or method invokation you can rely on Groovy dynamic nature.
There is no "cached source" or smth like that behind the scene and you can forget, from where your class is loaded. You can also cache classes, that are already compiled, and save them somewhere, as described [here]. It will drastically improve performance, if you need to load same class often.
But it will be better, to dig down in topic, because dynamic class loading is advanced Java/Groovy technique, it's whole infrastructure of chained classloaders, so it's better to refer documentation about them.
Links below may be helpful.
http://javarevisited.blogspot.ru/2012/12/how-classloader-works-in-java.html
How to use URLClassLoader to load a *.class file?
I'm writing an application that needs to reload a previously loaded class during runtime. The reason is that the class is auto-generated during runtime, and the new implementation changes the way the app works. I generate only one object of the said class, and I stripped it from all dependencies but an interface that defines constant values. There's no problem reseting the values of any or all of the members when reloading. I know exactly when it changes and I can control it. The only problem I have is the reload itself.
From what I read, I should use a ClassLoader. I tried to do so, but I can't make it work.
I tried the following:
Getting the current ClassLoader (myClassObject.getClass().getClassLoader()) and using it to reload the class - Doesn't work. It probably keeps loading the old implementation.
Generating my own (AKA copy-paste from SO with modifications) - Doesn't work because the ClassLoader I generate is different than the one that generated the class (Exception: myClass cannot be casted to myClass).
Creating a constructor that sets the ClassLoader of the superclass doesn't seem to have any effect.
Using my new ClassLoader to generate the class that has myClassObject as a member solved the ClassLoader mismatch for myClassObject, but created a new mismatch one level up. I used getClassLoader() everytime and I see they don't match.
I tried adding -Djava.system.class.loader=com.test.Reoader com.test.myMainClass to make it my default reloader, but I get an error from the compiler.
Google keeps pointing me back to the same stuff I read already.
EDIT: I tried creating an interface and reload the class implementing it. That didn't solve it either.
I know I should override the default ClassLoader, but nothing I do seems to succeed at that.
My ClassLoader:
public class Reloader extends ClassLoader {
public Reloader(){
super(Reloader.class.getClassLoader());
}
#Override
public Class<?> loadClass(String s) {
return findClass(s);
}
#Override
public Class<?> findClass(String s) {
try {
byte[] bytes = loadClassData(s);
return defineClass(s, bytes, 0, bytes.length);
} catch (IOException ioe) {
try {
return super.loadClass(s);
} catch (ClassNotFoundException ignore) {}
ioe.printStackTrace(java.lang.System.out);
return null;
}
}
private byte[] loadClassData(String className) throws IOException {
File f = new File("out\\production\\ManoCPU\\" + className.replaceAll("\\.", "/") + ".class");
int size = (int) f.length();
byte buff[] = new byte[size];
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
dis.readFully(buff);
dis.close();
return buff;
}
}
Thanks very much to anyone that can help.
You can only load a class once (per instance of a classloader). That means you have to throw away the classloader you have loaded your class with and instantiate a new one for your updated version of the class.
When dealing with multiple class loaders also have in mind that if you load the same class with several classloaders they are NOT recognized as being the same class.