Model for a Class that describes other Classes - java

I've got some problem that i can't figure out for a loong time.
I'm building web app in core-plugin architecture.
Plugins provides some functionality by methods. For example:
public void doSomething(Input input){
// Some functionality
}
The Input class can be basically anything. For example:
public class Input{
private String text;
private List<String> textList;
private InnerField inner;
private List<InnerField> innerList;
}
public class InnerField{
private String text;
pirvate Integer number;
}
The core module is collecting all methods of plugins and provides them to webpage user so the user can pick a method and set input data.
I know how to use java reflection api and get into metadata of methods and classes. The problem is with figuring out the structure of Class that would describe the Input and in same time store the data of Object.
In other words. I want to create a Class let's say InputData that i can pass to frontend which will:
build form based on fields declaration
fill form based on data
This InputData on submit would be serialized to json and saved in DB and, of course, should be mapped to original Input class so we can pass it to the plugin method.
I was thinking about something like this:
public class InputField{
private String className; //java.lang.String, some.package.CustomClass
private boolean variable; // if true, the strVal is a reference to other object (stored in map)
private String strVal; //value parsed to String if it's basic type like String, Integer, Boolean
private List<InputField> fields; //list of inner fields if it's complex type
}
And this would be good enough but only if the Input class would not have List types in it.
The one last kicker is that each field (even Input object itself) can be a referece to some variable.
So for example the user provided some values for Input class and want to reuse that so in form he just provides a name of the variable that it refers to. At the runtime when we invoke the plugin method the processor istead of parsing this json to data would search for data referenced by the variable name.
I know.. probably none of you know what i'm talking about but i'm in so awfull mindset that i can't even explain it well.
I am hoping that somone will kind of understand me and put me on the right tracks. Maybe someone had similar issue?
Edit: As requested below is short describtion what i really wanr to achive:
Basically i need a generic class in core module that will describe objects that are not known at compile time. From objects of this generic class i should be able to:
get metadata for building dynamic form in frontend and fill this form with data
map this object to original object (the one that is described by the generic class
generic class should be serializable (for example to json)
I "only" need help in generic class structure.

As i realized, thanks to Stephen, answers for "question" i asked would not be any help for anyone as i doubt someone would face exact same issue.
However, i figured out the right way to go for me. Frankly asking a question here was helpfull because trying to explain what i want achive made me think outside of the box.
Anyway. Earlier i was trying to keep Class definition along side with Object data in one Meta-Class. I separated those so i have class which holds definition about input class:
#Data
public class ObjectDefinition{
private String name;
private String path; // for example $root.myField.text, $root.listField[$idx].number
private Class type;
private boolean collection;
private boolean basicType;
private List<ObjectDefinition> fields; //only if this object is not basic
}
The values will be stored in a list of objects of class:
#Data
public class Field {
private String type;
private String path;
private String value;
private String var;
private boolean isCollection;
private int collectionSize;
}
Ugly? Maybe. Not efficent? Probably. Most important it will work and meets my requirements.

Related

Java class with member variable of type Object

Is it frowned upon to store a generic Object class within a class as a member variable? I have a use case where I have a Java class with the following member variables:
public class Request {
private String id;
private Object payload;
}
The payload needs to hold many different types of objects. For this example i'll just show two.
public class Entity {
private String entityId;
private String name;
}
public class User {
private String uid;
private String firstname;
private String lastname;
}
Ultimately, I need to create a list of Request objects List<Request> that can support internally storing generic payload objects. Using the Java generic T for the payload member variable in the Request class does not seem like a good approach because I need to be able to construct a list of Request objects that hold many different internal payload object types. What is the best way to handle this in Java?
I think it is still better to use generics in this case, rather than an Object. Since you will need to store many different Request objects which can contain different types of payloads, simply create a super class (or interface) which all of your payload classes inherit from, so that you can create your list as something like List<Request<Payload>> where each class (such as Entity and User) inherits from this Payload super class. This at least gives you the added benefit of your Request object not being able to contain just any Object as the payload, but rather an instance of the Payload class

where to put constant used in a java class?

I would like to know where to put constants which is only used in one java class? My code creates a name for a shared memory says "sharedMemory" , but I am not sure if I should put in separate Java file or just define in the same class as private static final String SHARED_MEMORY = "sharedMemory". I need this variable only in specific class. Also,if i define in same class should i make it static?
class ABC{
private static final String SHARED_MEMORY = "sharedMemory"; // OK to define in same class or in separate constants file
public void get(){
String name;
if(checIfSharedMemoryNeeded()){
name = SHARED_MEMORY;
}
}
private boolen checIfSharedMemoryNeeded(){
return (x.equals("yuiyr") && y.equals("yweir"))
}
}
Define constants that you only need in a single class in that class and make them private. You can make sure it will not accidentally be used anywhere else.
private static final String ONLY_FOR_THIS_CLASS = "only here";
Define constants that are contextually bound to a specific class but may be needed in other classes in that class they are contextually bound to, but make them public.
public static final String CONTEXTUALLY_FOR_THIS_CLASS_BUT_USABLE_ANYWHERE = "everywhere";
It will allow the usage in other classes like
String constantValueFromOtherClass = OtherClass.CONTEXTUALLY_FOR_THIS_CLASS_BUT_USABLE_ANYWHERE;
Think about writing an enum if the idea of a class that only holds public constants comes to your mind. In many cases, enums will be the better solution.
There are no common guidelines for what to do. Since it only used at one place, I recommend you to leave it in the class where it is used.
Unless you want to change the value in the future and you have many other hardcoded values that you want to change later, then I recommend that you make a class Config that holds all these values.
If this constant is only used for this class, then you should declare are the same class scope.
Now you gotta think if you are going to change the value in the future. If you do, and your application scales, it is better to create a .properties file to hold all the values and load to your app.
The general convention for non-global constants in Java is to write it with private static final like so:
class Foo {
private static final String bar = "foobar";
...
}
If you want to use this variable (SHARED_MEMORY) in ABC class then private access specifier is okay, and if this variable is part of your class not object then using static is a good idea.

Get Member/Fields of an existing Object

i will discribe my problem with the following example:
public class Person{
private int age;
private String name;
public Person(int age, String name){
this.age = age;
this.name = name;
}
}
I ve a class with some Members (age and name in this case) but i don't know which and how much my class does have. Also i don't even care about the amount or the types. I wan't to get all members of only one class. like this:
private List<Object> getAll(Class searchedClass, Object from){
// This is where the magic happens
}
This method shall return a List with every not null object which is an instance of the Class "searchedClass" and is a member of the Object "from".
In my case i've classes called Property and PropertyContainerList and an interface called PropertyContainer. A PropertyContainerList can only contain objects which implements my interface PropertyContainer. So a class could've 10 Properties as members and another one cuold've 5 but objects of both can be added. A Property has the method addListener(...). I want, every time an object is added to my list, to add an listener to every "Property"-member of the object. so like this:
if(instance of PropertyContainer is added){
List<Property> properties = getAll(Property.class, propertyContainerObject);
for(Property property : properties)
property.addListener(new Listener());
}
I tried a few things but i've no idea how to realize the getAll(Class, Object) method. Please help :)
Thanks for answers
Field f = Class.getDeclaredField("fieldname");
Object o = f.get(ObjectToGetMemberFrom);
This did it for me :)
What you probably need is reflection. Read the reflection trail in the Java tutorial.
Reflection allows you to inspect at runtime what member variables and functions a class has, and to read from and write to the member variables.
I recomend you have a look at this post:
Java - Get a list of all Classes loaded in the JVM
on how to load all classes in a certain package or the entire JVM.
Once a List of all loaded/ known classes is available you will have to:
1.) Check per class in the list if it is implementing the desired Interface
2.) If so use Reflection methods to read desired "members" (fields and/or methods) according to http://docs.oracle.com/javase/tutorial/reflect/class/classMembers.html
Also note that with reflection (it worked with JDK 1.4 lol...) you are possibly still able to change private to public at runtime to read all of those fields as well.
NOTE: To get a list of "all" classes i will rely on this google library rather than doing it all from scratch:
http://code.google.com/p/reflections/downloads/detail?name=reflections-0.9.9-RC1-uberjar.jar&can=2&q=

Create Fields and methods dynamically

I want to add new fields(variables) and encapsulating methods for a given class. For example: A class name Student has no any fields like below:
public class Student implements Serializable{
}
then in my application an instance is created;
Student s=new Student();
I want to add new methods which do not exist for student class at the run time.for example: I want to add a field called studentName, and getStudentName() and setStudentName() methods.
Then at the run time the student object will be like this;
public class Student implements Serializable{
private String studentName;
public void setStudentName(..){}
public String getStudentName(){return ...;}
}
In my application objects are written to a text file and all objects of same type do not have all variables. Therefore, I want to add only the required fields to save memory.
Any way is there a way to do this? Any sample code or link?
EDIT: or else can we create a class either and create instances which does not exists ?
EDIT 2: Thanks all of you answered and got many info and ideas. And changed the way to a better path from your suggestions as well
Why not just create a HashMap of values? Much more efficient, and has all the flexibility you're looking for.
public class Student
{
private HashMap<String, String> values;
public Student()
{
this.values = new HashMap<String, String>();
}
public void addValue(String name, String value)
{
values.put(name, value);
}
public String getValue(String name)
{
return values.get(name);
}
}
Why a HashMap?
You said that all objects may have differing values, and you'll be defining those new methods and attributes by a String. Well.. this will achieve that functionality without any horrible bytecode manipulation. For example:
String attrName = "name";
String attrValue = "jim";
Student stu = new Student();
stu.addValue(attrName, attrValue);
At the moment, you've only got the one value in your HashMap. The only overheard you have to face is the HashMap object itself, and two methods, which frankly is a fair trade off for a far tidier solution.
You can use bytecode instrumentation libraries like Javassist or ASM for this purpose. Here is an example of adding a field or method by using Javassist.
While it is possible with bytecode manipulation and such it wouldn't be wise, especially if you intend to do this to "save memory". It's unlikely that you would have so much data that it would make a difference, and if you did, you would store them in a database anyways.
Instead of writing your own HashMap based solution you can use DynaBean and DynaClass: support not only simple properties but also indexed (Array) and mapped (Map).
DynaBean can be introspected to get properties and values so you can dump to file BUT
with this solution you are only "simulating" a bean, your Student class doesn't really contains fields and accessors (you you call Student.getClass().getDeclaredField() you will get an empty array).
If you need to compose a "real" java java.lang.Class Javassist (my preferred choice, I used to resolve a solution similar to your question) or ASM (or CGLIB) are the best choiches.
I dont believe if this is possible in java but I'm sure it will only add to the memory because if you add them dynamically they must be set up beforehand + the code to add them dynamically.
Practically speaking, not in Java. In other languages like Javascript, this is possible.
Java is not a dynamic programming language and so I would not advice to follow that route even if some advance approaches may allow you to do so.
The Java idiom for that scenario would be to store the field values in a (hash) map instead. So you would have a couple of common accessors to set or get all attribute values and in the accessor you would need to indicate the name of the attribute you want to change.
However this solution won't save memory unless the maximum number of attributes is rather large and most object just have values for a small number of such attributes.
public class Entity {
// 5 is an estimate for the number attrs.
private Map<String,Object> attrs = new HashMap<>(5);
public Object getAttribute(String name) { return attrs.get(name); }
public void setAttribute(String name, Object obj) { attrs.put(name,obj); }
}
You could implement some runtime type-checking if you manage meta-data about possible attributes and their value types.

How to remove the dependency on a Java enum's values?

[Mind the gap: I know that the best solution would be to get rid of the enum completely, but that's not an option for today as mentioned in the comments, but it is planned for the (far) future.]
We have two deployment units: frontend and backend. The frontend uses an enum and calls an EJB service at the backend with the enum as a parameter. But the enum changes frequently, so we don't want the backend to know its values.
String constants
A possible solution would be to use String constants insteadof enums, but that would cause a lot of little changes at the frontend. I'm searching a solution, which causes as few changes as possible in the frontend.
Wrapper class
Another solution is the usage of a wrapper class with the same interface as an enum. The enum becomes an wrapper class and the enum values become constants within that wrapper. I had to write some deserialization code to ensure object identity (as enums do), but I don't know if it is a correct solution. What if different classloaders are used?
The wrapper class will implement a Java interface, which will replace the enum in the backend. But will the deserialiaztion code execute in the backend even so?
Example for a wrapper class:
public class Locomotion implements Serializable {
private static final long serialVersionUID = -6359307469030924650L;
public static final List<Locomotion> list = new ArrayList<Locomotion>();
public static final Locomotion CAR = createValue(4654L);
public static final Locomotion CYCLE = createValue(34235656L);
public static final Locomotion FEET = createValue(87687L);
public static final Locomotion createValue(long type) {
Locomotion enumValue = new Locomotion(type);
list.add(enumValue);
return enumValue;
}
private final long ppId;
private Locomotion(long type) {
this.ppId = type;
}
private Object readResolve() throws ObjectStreamException {
for (Locomotion enumValue : list) {
if (this.equals(enumValue)) {
return enumValue;
}
}
throw new InvalidObjectException("Unknown enum value '" + ppId + "'");
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (ppId ^ (ppId >>> 32));
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Locomotion)) {
return false;
}
Locomotion other = (Locomotion) obj;
if (ppId != other.ppId) {
return false;
}
return true;
}
}
Did you already had the same problem? How did you solved it?
Ok, let me see if I understand. You said that
"The frontend uses an enum and calls
an EJB service at the backend with the
enum as a parameter. But the enum
changes frequently, so we don't want
the backend to know its values"
When you say "values" I assume you are referring to the numeric value you pass in the enum constructor and not to the enum constants themselves.
Therefore, this implies that the frontend and the backend will have two different versions of the enum class, but the enum constants in them will be the same.
I am only assuming the communication is via RMI (but this is not entirely clear in your post).
Now, serialization/deserialization of enums works different than with other objects. According to the Java Serialization Specification, when a enum is serialized, only its name is serialized. And when it is deserialized, it is built using the Enum.valueOf(name) method.
So, your original wrapper proposal would not work, because the server, due to stipulated serialization of Enums will never know the actual value of the enums in the client.
Bottom line, if you intend to pass an enum to the server there is no possible way to do what you pretend to do because the values in the frontend will never reach the backend if serialization is implied.
If RMI is implied, a good solution would be to use code mobility, this way you could place the problematic class in a repository accessible to both, server and client, and when the frontend developers change the class definition, you can publish the class in the repository and the server can get it from there.
See this article about dynamic code downloading using code base property in RMI
http://download.oracle.com/javase/6/docs/technotes/guides/rmi/codebase.html
Another possible solution is that you could stop using a Java Enum and use Java class with final constants, as we used to do in the old days before enums, and that way you can ensure that its values will be properly serialized when they are are sent to the backend.
Somewhat like this
public class Fruit implements Serializable{
private static final long serialVersionUID = 1L;
public final Fruit ORANGE = new Fruit("orange");
public final Fruit LEMON = new Fruit("lemon");
private String name;
private Fruit(String name){
this.name = name;
}
}
This way you can be in full control of what happens upon deserialization and your wrapper pattern might work this way.
This type of construction cannot substitute an enum completely, for instance, it cannot be used in switch statements. But, if this is an issue, you could use this object as the parameter sent to the server, and let the server rebuild the enum out of it with its version of the enum class.
Your enum, therefore, could have two new methods, one to build Java instances out of the enum itself:
public static Fruit toFruit(FruitEnum enum);
public FruitEnum valueOf(Fruit fruit);
And you can use those to convert back and forth versions of the parameter for the server.
It's an odd request, as i would think the server should know about the values of what is going into the database, but ok, i'll play along. Perhaps you could do this
public enum Giant {Fee, Fi, Fo, Fum};
public void client() {
Giant giant = Giant.Fee;
server(giant);
}
public void server(Enum e) {
String valueForDB = e.name();
//or perhaps
String valueForDB = e.toString();
}
For data transfer between frontend and backend both need to use the same class versions because of possible serialization during marshalling parameters. So again they have to know exactly the same enums or whatever other classes you try to use. Switching enums to something different won't work either. You have to set on a known class identiy for both.
So if the server should do actions based on some kind of processing/calculating the values of the parameters use strings or whatever other non-changing class you decide on and put your values inside: string of characters, array of numbers or whatever.
So if you put your database id inside the wrapper object the server will be able to get the objects out of the database. But still - they both need exact the same version of the wrapper class in their classpaths.
Okay, I can't be too exact because I don't see your code but in my experience something that changes like that should be external data, not enums.
What I almost always find is that if I externalize the information that was in the enums, then I have to externalize a few other pieces as well, but after doing it all I end up factoring away a LOT of code.
Any time you actually use the values of an enum you are almost certainly writing duplicate code. What I mean is that if you have enums like "HEARTS", "DIAMONDS"...
The ONLY way they can be used in your code is in something like a switch statement:
switch(card.suit)
case Suit.HEARTS:
load_graphic(Suit.HEARTS);
// or better yet:
Suit.HEARTS.loadGraphic();
break;
case Suit.SPADES:
Suit.SPADES.loadGraphic();
...
Now, this is obviously stupid but I made the stupid constraint to say that you USED the values in the code. My assertion is that if you don't USE the values you don't need an enum--Let's not use the values in code and see:
card.suit.loadGraphic();
Wow, all gone. But suddenly, the entire point of using an enum is gone--instead you get rid of the whole class preload a "Suit" factory with 4 instances from a text file with strings like "Heart.png" and "Spade.png".
Nearly every time I use enums I end up factoring them out like this.
I'm not saying there isn't any code that can benefit from enums--but the better that I get at factoring code and externalizing data, the less I can imagine really needing them.

Categories