473,513 Members | 2,665 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Need help with beans - adding properties at run time???

Hi everyone,

I am rather new to Java beans. Just picked up a book last night and
started reading about them. I am building an application that allows a
user to define objects with dynamic properties. Something similar to a
java hash table. One can add new properties at runtime and remove them
as well.

I have a really fancy third party property inspector available to me
that I would very much like to reuse. This inspector uses beans API.
My hope was that I could build a set of Java bean wrappers for my
dynamic objects such that they could be inspectable in this inspector.

Well, from what I read so far it seams that I have to have a getXXX and
setXXX method defined in my wrapper class for every property I want to
inspect. I can not define these methods since I have no idea what
properties the user might add to my original object. Is there any way
to work around this difficulty?

Any help is appreciated.

Nik
--
=======================================
Nikita A. Visnevski
Adaptive Systems Laboratory
CRL, McMaster University
Phone : (905) 525-9140 x 27282
Web : http://soma.crl.mcmaster.ca
=======================================

Jul 17 '05 #1
10 3744
On Mon, 19 Apr 2004 07:53:53 -0400, "Nikita A. Visnevski"
<vi****@soma.crl.mcmaster.ca> wrote:
Hi everyone,

I am rather new to Java beans. Just picked up a book last night and
started reading about them. I am building an application that allows a
user to define objects with dynamic properties. Something similar to a
java hash table. One can add new properties at runtime and remove them
as well.

I have a really fancy third party property inspector available to me
that I would very much like to reuse. This inspector uses beans API.
My hope was that I could build a set of Java bean wrappers for my
dynamic objects such that they could be inspectable in this inspector.

Well, from what I read so far it seams that I have to have a getXXX and
setXXX method defined in my wrapper class for every property I want to
inspect. I can not define these methods since I have no idea what
properties the user might add to my original object. Is there any way
to work around this difficulty?


The only thing I can think of is using java reflection and proxy
methods... That would be a bit complicated though.

I, personally, would us a hashtable or something to map a property to
a value.

--
now with more cowbell
Jul 17 '05 #2
Nikita A. Visnevski wrote:
Well, from what I read so far it seams that I have to have a getXXX and
setXXX method defined in my wrapper class for every property I want to
inspect. I can not define these methods since I have no idea what
properties the user might add to my original object. Is there any way
to work around this difficulty?


In the end, you'll have to provide a pair of accessor/mutator methods
for each property. You don't have to call them setXXX and getXXX is you
don't want to (see BeanInfo for an alternate way to specify these
methods if they have different names), but you do need for them to
exist.

One way around this, if you're very determined, may be for you to
generate a JavaBeans wrapper class around your original table-like
object. You'd need to do some Java code generation, and BCEL would be
very helpful in accomplishing this. Essentially, you'd want to generate
a class whose objects hold a reference to your original object and
expose a set of methods that look like JavaBeans methods. These methods
would pass their operations through to your original object. You'd need
to generate the bean class and object on the fly whenever you want to
inspect the data as if it were a JavaBean.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
Jul 17 '05 #3


Chris, Bryce,

thanks for your replies. I just arrived at the same conclusion
regarding the on-the-fly code generation. The idea of the Proxy object
seemed very attractive, but when I dug deeper I realized that everything
boils down to the interface with accessor/mutator methods that I would
have to provide. Well, it is exactly the interface that I do not have.
So, I suppose, my choices are:
1. Generate interfaces or perhaps even the entire BeanInfo classes on
the fly.
2. Abandon this idea altogether and write my own inspector for
inspecting Java hashtable-like objects.

Neither 1, nor 2 sound very exciting :(

Here is a question (since I have never done something like that before).
Suppose I can generate an interface on the fly into a java file. I
would have to compile it. Suppose I already have a class with the same
name loaded into jvm. Can I unload/reload/update it with the new class,
or should I just create and load an entirely new class with new name and
forget about the old one?

Thanks in advance.

Nik

Chris Smith wrote:
In the end, you'll have to provide a pair of accessor/mutator methods
for each property. You don't have to call them setXXX and getXXX is you
don't want to (see BeanInfo for an alternate way to specify these
methods if they have different names), but you do need for them to
exist.

One way around this, if you're very determined, may be for you to
generate a JavaBeans wrapper class around your original table-like
object. You'd need to do some Java code generation, and BCEL would be
very helpful in accomplishing this. Essentially, you'd want to generate
a class whose objects hold a reference to your original object and
expose a set of methods that look like JavaBeans methods. These methods
would pass their operations through to your original object. You'd need
to generate the bean class and object on the fly whenever you want to
inspect the data as if it were a JavaBean.


--
=======================================
Nikita A. Visnevski
Adaptive Systems Laboratory
CRL, McMaster University
Phone : (905) 525-9140 x 27282
Web : http://soma.crl.mcmaster.ca
=======================================

Jul 17 '05 #4
Chris,

I just thought of something interesting reflecting upon your message:

Chris Smith wrote:
In the end, you'll have to provide a pair of accessor/mutator methods
for each property. You don't have to call them setXXX and getXXX is you
don't want to (see BeanInfo for an alternate way to specify these
methods if they have different names), but you do need for them to
exist.


Instead of providing a pair for each property, is there a way to define
one accessor and one mutator method in the BeanInfo, that would somehow
be able to handle all properties. That would include:

1. In the BeanInfo, mapping all accessors to one method, and all
mutators to the other
2. Distinguishing within the accessor/mutator methods which property
they were called for.

As I said, I have a very limited Java beans experiance, but this is how
I would've done that in C/C++ or some other language.

Thanks,

Nik

--
=======================================
Nikita A. Visnevski
Adaptive Systems Laboratory
CRL, McMaster University
Phone : (905) 525-9140 x 27282
Web : http://soma.crl.mcmaster.ca
=======================================

Jul 17 '05 #5
Nikita A. Visnevski wrote:
Here is a question (since I have never done something like that before).
Suppose I can generate an interface on the fly into a java file. I
would have to compile it. Suppose I already have a class with the same
name loaded into jvm. Can I unload/reload/update it with the new class,
or should I just create and load an entirely new class with new name and
forget about the old one?


First of all, I'd suggest not creating a Java source file and then
compiling. Instead, generate the bytecode directly. You then don't
need to worry about a compiler at all; and a bytecode loader is a
required piece of any compliant JVM. If you generate interfaces and
then implement them with java.lang.reflect.Proxy, then this should not
be too awfully difficult.

As for name conflicts, you can generate the interface using its own
ClassLoader. This avoids naming conflicts with other classes in the
system.

For bytecode generation, look at http://jakarta.apache.org/bcel/.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
Jul 17 '05 #6
Hi Chris,

thanks for your help. I have a few more points to clarify:

Chris Smith wrote:
As for name conflicts, you can generate the interface using its own
ClassLoader. This avoids naming conflicts with other classes in the
system.
I guess I did not really make myself clear (my ignorance in the
functionality of JVMs is to blame I suppose). When I asked about
reloading/updating classes, I meant in fact the following.

Suppose I have a byte-code of an already compiled class. Let's call it
Foo.class. In my application I instantiate an object of this class (or
load this class in some other way - system ClassLoader, Class.forName
method, etc.). Suppose at some point in time later I have to change
this class. Suppose I use this BCEL package to generate bytecode of the
new class. From what I understand, the last step will just
update/recreate the Foo.class file, am I right? If I am right, how do I
then update this class within the JVM? Is there an analog of reloading
the class from the newly created bytecode? Perhaps I simply
misunderstand something and matter is simpler than it appears to me. I
just do not understand how do I now use this new bytecode for a class
that has already previously been loaded into JVM.

For bytecode generation, look at http://jakarta.apache.org/bcel/.


Thanks a lot for this link. I might go for it and try to generate
interfaces on the fly and use the Proxy object to create the beans.

Thank you for your help once again.

Nik

--
=======================================
Nikita A. Visnevski
Adaptive Systems Laboratory
CRL, McMaster University
Phone : (905) 525-9140 x 27282
Web : http://soma.crl.mcmaster.ca
=======================================

Jul 17 '05 #7
Nikita A. Visnevski wrote:
I guess I did not really make myself clear (my ignorance in the
functionality of JVMs is to blame I suppose). When I asked about
reloading/updating classes, I meant in fact the following.

Suppose I have a byte-code of an already compiled class. Let's call it
Foo.class. In my application I instantiate an object of this class (or
load this class in some other way - system ClassLoader, Class.forName
method, etc.). Suppose at some point in time later I have to change
this class. Suppose I use this BCEL package to generate bytecode of the
new class. From what I understand, the last step will just
update/recreate the Foo.class file, am I right? If I am right, how do I
then update this class within the JVM? Is there an analog of reloading
the class from the newly created bytecode? Perhaps I simply
misunderstand something and matter is simpler than it appears to me. I
just do not understand how do I now use this new bytecode for a class
that has already previously been loaded into JVM.
I think my previous answer applies. You can never change a class in the
JVM once it's been loaded (except through means intended for debuggers
and the like, which you don't want to use for this). What you'd do is
separate your object from the JavaBean, and then create new JavaBean
objects as required.

If you're following my advice, when you create these new JavaBean
objects, you will not do it with Class.forName or the system
ClassLoader. You'll do it with a new ClassLoader that you've created
for exactly that purpose. Each time you need to update the JavaBean
with a different set of properties, you will create a new ClassLoader
and discard the old one, leaving it for the garbage collector. Naming
conflicts will never be an issue, since you'll only load one class with
that ClassLoader.
Thanks a lot for this link. I might go for it and try to generate
interfaces on the fly and use the Proxy object to create the beans.


That would be my recommendation.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
Jul 17 '05 #8
Hi Chris,

well, I just started playing with the BCEL package. I was totally
confused before. Stuff seems to work really well. I really enjoy the
package. This is exactly what I need. Thank you very much once again.

Nik

Chris Smith wrote:
I think my previous answer applies. You can never change a class in the
JVM once it's been loaded (except through means intended for debuggers
and the like, which you don't want to use for this). What you'd do is
separate your object from the JavaBean, and then create new JavaBean
objects as required.

If you're following my advice, when you create these new JavaBean
objects, you will not do it with Class.forName or the system
ClassLoader. You'll do it with a new ClassLoader that you've created
for exactly that purpose. Each time you need to update the JavaBean
with a different set of properties, you will create a new ClassLoader
and discard the old one, leaving it for the garbage collector. Naming
conflicts will never be an issue, since you'll only load one class with
that ClassLoader.


--
=======================================
Nikita A. Visnevski
Adaptive Systems Laboratory
CRL, McMaster University
Phone : (905) 525-9140 x 27282
Web : http://soma.crl.mcmaster.ca
=======================================

Jul 17 '05 #9
Nikita A. Visnevski wrote:
well, I just started playing with the BCEL package. I was totally
confused before. Stuff seems to work really well. I really enjoy the
package. This is exactly what I need. Thank you very much once again.


Well, I found your project interesting here's basically what you need.
Just call createBean and pass it a list of the bean properties and an
instance of BeanAdapter that knows how to store and retrieve bean data.
It's not perfect, but it's a start. Someone with more knowledge of the
JavaBeans specification could probably do a better job of getting all
the border cases right.
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.apache.bcel.Constants;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.Type;

public class DynamicBeanFactory implements Constants
{
private static final class BeanInvocationHandler
implements InvocationHandler
{
private final BeanAdapter adapter;

private BeanInvocationHandler(BeanAdapter adapter)
{
this.adapter = adapter;
}

public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable
{
String methodName = method.getName();
if (methodName.startsWith("set"))
{
String propName =
Character.toLowerCase(methodName.charAt(3))
+ methodName.substring(4);
adapter.setProperty(propName, args[0]);
return null;
}
else if (methodName.startsWith("get"))
{
String propName =
Character.toLowerCase(methodName.charAt(3))
+ methodName.substring(4);
return adapter.getProperty(propName);
}
else if (methodName.startsWith("is"))
{
String propName =
Character.toLowerCase(methodName.charAt(2))
+ methodName.substring(3);
return adapter.getProperty(propName);
}

throw new RuntimeException(method.toString());
}
}

public static interface BeanAdapter
{
public void setProperty(String name, Object value);
public Object getProperty(String name);
}

public static Object createBean(
String[] propNames,
Class[] propTypes,
BeanAdapter adapter)
{
final String CLASS_NAME = "net.twu.cdsmith.BeanInterface";
ClassGen cg = new ClassGen(
CLASS_NAME, "java.lang.Object", null,
ACC_PUBLIC | ACC_INTERFACE | ACC_ABSTRACT,
new String[] { });
ConstantPoolGen cp = cg.getConstantPool();

ByteArrayOutputStream out = new ByteArrayOutputStream();

for (int i = 0; i < propNames.length; i++)
{
String methodName;

if (propTypes[i] == boolean.class)
{
methodName = "is"
+ Character.toUpperCase(propNames[i].charAt(0))
+ propNames[i].substring(1);
}
else
{
methodName = "get"
+ Character.toUpperCase(propNames[i].charAt(0))
+ propNames[i].substring(1);
}

Type t = Type.getType(propTypes[i]);

InstructionList il = new InstructionList();
MethodGen method = new MethodGen(ACC_PUBLIC | ACC_ABSTRACT,
t, Type.NO_ARGS, new String[] { },
methodName, CLASS_NAME, il, cp);
method.setMaxStack();
method.setMaxLocals();
cg.addMethod(method.getMethod());
il.dispose();
}

for (int i = 0; i < propNames.length; i++)
{
String methodName = "set"
+ Character.toUpperCase(propNames[i].charAt(0))
+ propNames[i].substring(1);

Type t = Type.getType(propTypes[i]);

InstructionList il = new InstructionList();
MethodGen method = new MethodGen(ACC_PUBLIC | ACC_ABSTRACT,
Type.VOID, new Type[] { t }, new String[] { "arg" },
methodName, CLASS_NAME, il, cp);
method.setMaxStack();
method.setMaxLocals();
cg.addMethod(method.getMethod());
il.dispose();
}

try
{
cg.getJavaClass().dump(out);
}
catch (IOException e)
{
throw new RuntimeException(e);
}

final byte[] classData = out.toByteArray();
ClassLoader loader = new ClassLoader() {
protected Class findClass(String name)
throws ClassNotFoundException
{
return defineClass(
name, classData, 0, classData.length);
}
};

try
{
Class ifcClass = loader.loadClass(CLASS_NAME);
return Proxy.newProxyInstance(
loader, new Class[] { ifcClass },
new BeanInvocationHandler(adapter));
}
catch (ClassNotFoundException e)
{
throw new RuntimeException(e);
}
}
}

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
Jul 17 '05 #10
WOW!!! Thanks Chris,

I have started playing with your example. I have not made it work yet
for my needs, but I think I am on the right track. I am going to resume
tomorrow and see how far I can get with this stuff. The sample that you
created makes a lot of sense and it seems like it is exactly what I need.

If you are really interested in my project, I can give you a few more
details. I am actually developing an electronic warfare software
prototype of a radar warning receiver for my Ph.D. thesis. The software
is mostly written in Matlab/Simulink as well as C/C++. It does some
really cool stuff, but it lacks any kind of user interface at this
point. Radar emitter library that I have created is customizable
through a set of files that contain property-value pairs. I have a
customer for the prototype - Canadian Defence Department. They are
paying for my studies and want some nice GUI on top of the project. I
am allowed to see some emitter definition files, but others have a high
military clearance requirement, and I have no access to them. God only
knows what parameters they define there.

So, Matlab has this property inspector built in that is JavaBeans
compliant. I have developed a set of flexible Matlab objects to
represent emitter library entries, but in order for me to inspect them
in the Matlab's inspector, I have to create java bean wrappers for my
Matlab objects the structure of which I do not necessarily know. I hope
that I can make it work using the example that you gave me. This would
be the cleanest and most painless solution to the GUI front end for my
project.

Anyhow, thank you very much once again for your help.

Nik

Chris Smith wrote:
Well, I found your project interesting here's basically what you need.
Just call createBean and pass it a list of the bean properties and an
instance of BeanAdapter that knows how to store and retrieve bean data.
It's not perfect, but it's a start. Someone with more knowledge of the
JavaBeans specification could probably do a better job of getting all
the border cases right.

--
=======================================
Nikita A. Visnevski
Adaptive Systems Laboratory
CRL, McMaster University
Phone : (905) 525-9140 x 27282
Web : http://soma.crl.mcmaster.ca
=======================================

Jul 17 '05 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
2254
by: Phil Powell | last post by:
Ok, I installed ANT, I have c:\ant in my ANT_HOME environment variable, I have c:\ant\bin in my PATH environmental variable, I installed the JAR files for TCL and for Javascript (Rhino)... to no...
0
9858
by: James Hong | last post by:
Help please, I try to sending an email from my html page using the java applet. but it give error on most of the PC only very few work, what is the error i make the java applet show as below ...
8
4191
by: Johnny Knoxville | last post by:
I've added a favicon to my site (http://lazyape.filetap.com/) which works fine if you add the site to favourites the normal way, but I have some JavaScript code on a couple of pages with a link,...
3
1577
by: Mike | last post by:
Hey guys I am pulling my hair out on this problem!!!!! Any help or ideas or comments on how to make this work I would be grateful! I have been working on this for the past 4 days and nothing I do...
5
3472
by: Benne Smith | last post by:
Hi, I have three enviroments; a development, a testing and a production enviroment. I'm making a big application (.exe), which uses alot of different webservices. I don't use the webservices...
8
7171
by: Marc | last post by:
Hi! I'm calling a web service using C# and a wrapper class generated by wsdl tool. The web service specification contains some nillable parameters which types are Value Types in .NET (long, int,...
4
1792
by: Saurabh Aggrawal | last post by:
Hi, I have made a dll and it is working fine in the debug build (as expected) but when I run it in the release build it is working strangely. For example, the dll saves the 10 properties on the...
2
1482
dmjpro
by: dmjpro | last post by:
I have five source files. public class SpringAOP implements SpringAOPInterface { public void showMessage() { System.out.println("I m learning Spring+AOP, & i really enjoying...
1
7078
by: =?ISO-8859-1?Q?Lasse_V=E5gs=E6ther_Karlsen?= | last post by:
I get the above error in some of the ASP.NET web applications on a server, and I need some help figuring out how to deal with it. This is a rather long post, and I hope I have enough details that...
0
7257
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
7157
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
7521
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
5682
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
1
5084
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
4745
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
3232
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
1
798
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
455
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.