How to generate class file with dynamic property names - java

Suppose I have source java template as:
public class Class1 {
private String field1;
private int field2;
}
In my main method I want to generate above template java class as follows
It should generate separate MyClass.java file in different location
Class1 should be replace as MyClass
field1 should be replace as property1
field2 should be replace as property2
Example:
public class MyClass{
private String property1;
private int property2;
}
Is there any framework to achieve this? We can give dynamic names in xml file .

Maybe you are looking at http://commons.apache.org/proper/commons-bcel/index.html
The Byte Code Engineering Library (Apache Commons BCEL™) is intended to give users a convenient way to analyze, create, and manipulate (binary) Java class files (those ending with .class). Classes are represented by objects which contain all the symbolic information of the given class: methods, fields and byte code instructions, in particular.
Here https://www.programcreek.com/java-api-examples/index.php?api=org.apache.bcel.generic.ClassGen you can find some examples of how to use ClassGen
This article also could be useful https://www.ibm.com/developerworks/java/library/j-dyn0414/.

Related

How to dynamically generate a Java Bean class using plain Java?

I went through some of the samples that have used libraries to generate bean classes from JSON, XML etc. What I would like to know is, whether there's a way to dynamically generate a java bean class, with the parameters I give?
For example if I give an array of Strings as arguments which would represent the properties of the Pojo class for now, how can I generate the POJO?
Arguments: {"field1", "field2", "field3"}
Generate POJO would be:
public class TestBean {
private String field1;
TestBean() {
}
public String getField1() {
return field1;
}
public void setField1(String field1) {
this.field1 = field1;
}
}
It should be the same for field2 and field3 as well.
Here I'm assuming that all the properties above are String and the class name is constant for now. Is there any way I can achieve this? Thanks in advance.
The problem with generating an actual Java class at runtime is that there is no way you can access it using standard Java syntax as the compiler doesn't know about it.
In practice therefore, most people just use a map in this circumstance. The only case I can think where you would need to generate a real class is where there is some other code you can't change that requires a Java object and inspects it dynamically using reflection or otherwise.
If you don't need this you are better off using a map, or possibly some utility class designed to emulate a Java Bean.
The Apache BeanUtils package provides the DynaBean interface to implement dynamic Java Beans. That said, the classes are only recognised as beans if accessed from the rest of the BeanUtils package.
There are several subclasses depending on what you want, for example, LazyDynaBean:
DynaBean myBean = new LazyDynaBean();
myBean.set("myProperty", "myValue");

Recommended way to generate a java file from another java file

Let us consider that I have a file which looks like following:
#CreateFieldClass
public class Queue {
private String queueId;
private int order;
private boolean isActive;
/* Getters and Setters */
}
What I want is, If there is #CreateFieldClass annotation, I want to generat a new java file, in the same package which would look something like this
public class QueueFields {
public static final Field<Queue, String> QUEUE_ID = new Field<>(Queue.class, "queueId", DataType.STRING);
public static final Field<Queue, Integer> ORDER = new Field<>(Queue.class,"order", DataType.NUMBER);
public static final Field<Queue, Boolean> IS_ACTIVE = new Field<>(Queue.class,"isActive", DataType.Boolean);
}
I have a mapping of Java type to the "DataType" mentioned above.
I know ASM is one option to consider, but are there any better recommendations or even some ASM tutorials/examples someone can help me out.
To examine the annotated class, you can use reflection. Be aware that any fields that use generics will lose the generic parameter types due to erasure (if you need to get around that, then you need to parse the source code and work off of the parse tree). To generate the resulting class, you can do basic String concatenation. If you want a more structured method for generating code, I like the codemodel library.

Add "symbol" field to Java class

I have a library, I have to tag a class with certain field dynamically (code generation) and I don't want the meta-data field names I generate to clash with user-defined field names.
Using JavaScript, we can use ES6 Symbols to do this. We can create getters/setters and retrieve fields using Symbols and in this way prevent name-clashing.
So using JS, it might look like:
export class Foo {
static libraryDefinedField = Symbol('lib.defined')
userDefinedField = 'whatev';
setLibraryDefinedField(v){
this[Foo.libraryDefinedField] = v;
}
getLibraryDefinedField(v){
return this[Foo.libraryDefinedField];
}
}
is there a way to do this with Java somehow - create instance or static fields on a class that won't conflict with user-defined fields?
Note that using JS, if there were user-generated static field properties and we wanted to prevent nameclashing, we might do this:
// put the symbol outside the class, so even static properties won't conflict
const libraryDefinedField = Symbol('lib.defined');
export class Foo {
userDefinedField = 'whatev';
setLibraryDefinedField(v){
this[libraryDefinedField] = v;
}
getLibraryDefinedField(v){
return this[libraryDefinedField];
}
}
Java has no notion of symbols the way ES6 has.
If you simply want to "tag" a class, why not consider making the class implement an (possibly empty) interface? Class and interface names are unique.

How can I make pre-configured templates using XStream

I am currently developing a system that uses XStream to create objects from XML. An example object would be
#XStreamAlias("TestClass")
public class TestClass{
#XStreamAlias("format")
private String format;
public String getFormat(){
return format;
}
public void setFormat(String format){
this.format = format;
}
}
This class has one field, a format field, and the XML from which it would be constructed would look like:
<TestClass>
<format>foo</format>
</TestClass>
Now I would like to instantiate different instances of this class, with a specific format. For instance I would like a TestClass object with format foo and one with format bar. But instead of producing
<TestClass>
<format>foo</format>
</TestClass>
<TestClass>
<format>bar</format>
</TestClass>
I want to use an alias system of some sort so that the above XML would not be necessary but instead I could use
<TestClassFoo />
<TestClassBar />
where of course the name does not need to include the format specified.
I see that there has to be a custom converter, but I again do not want to hard code every alias, but instead load these from XML as well (yes, it get complicated). The result of this would be to create shortcut templates for different XML objects, which can be configured dynamically.
If your goal is more compact XML, why not use #XStreamAsAttribute so you will get output like <TestClass format="foo"/>? Otherwise, yes, you are going to have to write a custom converter to do exactly what you want.

How do I alias the scala setter method 'myvar_$eq(myval)' to something more pleasing when in java?

I've been converting some code from java to scala lately trying to teach myself the language.
Suppose we have this scala class:
class Person() {
var name:String = "joebob"
}
Now I want to access it from java so I can't use dot-notation like I would if I was in scala.
So I can get my var's contents by issuing:
person = Person.new();
System.out.println(person.name());
and set it via:
person = Person.new();
person.name_$eq("sallysue");
System.out.println(person.name());
This holds true cause our Person Class looks like this in javap:
Compiled from "Person.scala"
public class Person extends java.lang.Object implements scala.ScalaObject{
public Person();
public void name_$eq(java.lang.String);
public java.lang.String name();
}
Yes, I could write my own getters/setters but I hate filling classes up with that and it doesn't make a ton of sense considering I already have them -- I just want to alias the _$eq method better. (This actually gets worse when you are dealing with stuff like antlr because then you have to escape it and it ends up looking like person.name_\$eq("newname");
Note: I'd much rather have to put up with this rather than fill my classes with more setter methods.
So what would you do in this situation?
You can use Scala's bean property annotation:
class Person() {
#scala.reflect.BeanProperty
var name:String = "joebob"
}
That will generate getName and setName for you (useful if you need to interact with Java libraries that expect javabeans)

Categories

Resources