I originally wrote:
At 3:39 AM -0400 3/29/09, Stephen Bannasch wrote:
>Here's a simple example of doing OTrunk model class reflection using JRuby
>
> http://gist.github.com/87311
>
>I really like how simple it looks (after I figured out how to do it).
>
>I'm going to see if I can use this to generate both models and otml
>and html view templates in the RITES Rails app.
Scott replied:
>That approach won't work for all the ot classes. They are not all
>interfaces that simply define their otrunk properties. Some of them are
>classes that have a inner-interface which defines the otrunk properties.
>
>You would be better off using the existing OTrunk reflection api to do
>this. For a simple example of this take a look at:
>org.concord.otrunk.xml.SchemaGenerator
>in the otrunk project.
We have different definitions of simple ;-)
>That class basically does what your jruby code is doing. And it will
>work with any OTClass not just the simple ones.
Are you talking about this method: getOTAllClassProperties
which returns an array of these (implemented):
public interface OTClassProperty
{
String getName();
OTType getType();
Object getDefault();
boolean isPrimitive();
boolean isList();
boolean isMap();
boolean isOnlyInOverlayProperty();
public boolean isOverriddenProperty();
public OTClassProperty getOnlyInOverlayProperty();
public OTClassProperty getOverriddenProperty();
}
Which reference constants defined here?
public class OTCorePackage
{
public final static OTPrimitiveType BOOLEAN_TYPE =
new OTPrimitiveTypeImpl(TypeService.BOOLEAN, Boolean.class);
public final static OTPrimitiveType INTEGER_TYPE =
new OTPrimitiveTypeImpl(TypeService.INTEGER, Integer.class);
public final static OTPrimitiveType LONG_TYPE =
new OTPrimitiveTypeImpl(TypeService.LONG, Long.class);
public final static OTPrimitiveType FLOAT_TYPE =
new OTPrimitiveTypeImpl(TypeService.FLOAT, Float.class);
public final static OTPrimitiveType DOUBLE_TYPE =
new OTPrimitiveTypeImpl(TypeService.DOUBLE, Double.class);
public final static OTPrimitiveType BLOB_TYPE =
new OTPrimitiveTypeImpl(TypeService.BLOB, BlobResource.class);
public final static OTPrimitiveType STRING_TYPE =
new OTPrimitiveTypeImpl(TypeService.STRING, String.class);
public final static OTPrimitiveType XML_STRING_TYPE =
new OTPrimitiveTypeImpl(TypeService.XML_STRING, OTXMLString.class);
public final static OTListType OBJECT_LIST_TYPE =
new OTListTypeImpl(OTObjectList.class);
public final static OTListType RESOURCE_LIST_TYPE =
new OTListTypeImpl(OTResourceList.class);
public final static OTMapType OBJECT_MAP_TYPE =
new OTMapTypeImpl(OTObjectMap.class);
public final static OTMapType RESOURCE_MAP_TYPE =
new OTMapTypeImpl(OTResourceMap.class);
}
Against my better judgment I'll take the bate...
The total number of lines of code is about the same, (gist is down so I
can't compare actual lines) if you strip out xml parsing used to find
the list of imports. In your code you were statically defining the list
of classes so stripping out the xml parsing seems legit.
Can you post your code to confluence or somewhere more reliable/speedy
than gist?
>
>> That class basically does what your jruby code is doing. And it will
>> work with any OTClass not just the simple ones.
>>
>
> Are you talking about this method: getOTAllClassProperties
>
> which returns an array of these (implemented):
>
> public interface OTClassProperty
> {
>
.. snip ..
> }
>
> Which reference constants defined here?
>
> public class OTCorePackage
> {
>
.. snip ...
> }
>
Yes. That is part of the reflection API that I was talking about. But
it seems easier to talk about by looking at how you use it, instead of
looking at its implementation. The SchemaGenerator class is a pretty
simple example of using it. Don't confuse SchemaGenerator with
RNGSchemaGenerator, RNGSchemaGenerator is more complicated because it is
trying to map to RNG instead of just simply printing like you and
SchemaGenerator do.
Basically instead of using Java/JRuby reflection to find the methods and
then find the properties you use OTrunk's reflection. So once you have
an OTClass you can find its properties and once you have a property you
can find its type and default value.
Here is an example of that (basically taken from SchemaGenerator):
http://confluence.concord.org/display/CSP/OTrunk+Reflection
Scott
Sorry ... it's a fun game to play ... and both of us are terribly
easy to hook ;-)
>The total number of lines of code is about the same, (gist is down so I
>can't compare actual lines) if you strip out xml parsing used to find
>the list of imports. In your code you were statically defining the list
>of classes so stripping out the xml parsing seems legit.
The xml parsing doesn't add much ...
>Can you post your code to confluence or somewhere more reliable/speedy
>than gist?
gist is pretty good -- gists themselves can be updated and forked --
there are some backbone routers down right now
http://confluence.concord.org/display/CSP/otrunk+reflection+using+JRuby
>Yes. That is part of the reflection API that I was talking about. But
>it seems easier to talk about by looking at how you use it, instead of
>looking at its implementation. The SchemaGenerator class is a pretty
>simple example of using it. Don't confuse SchemaGenerator with
>RNGSchemaGenerator, RNGSchemaGenerator is more complicated because it is
>trying to map to RNG instead of just simply printing like you and
>SchemaGenerator do.
>
>Basically instead of using Java/JRuby reflection to find the methods and
>then find the properties you use OTrunk's reflection. So once you have
>an OTClass you can find its properties and once you have a property you
>can find its type and default value.
>
>Here is an example of that (basically taken from SchemaGenerator):
>http://confluence.concord.org/display/CSP/OTrunk+Reflection
Thanks. I was looking at RNGSchemaGenerator.
I updated that page with a second script which uses the OTrunk
reflection mechanism.
A few things to note about the script:
- it uses a simple eval() to access the java class given its string
name. I looked for several ways to do this, and in the end eval seemed
the best option. The approach being taking by the original script would
run into problems if more than one class had the same simple name.
- it uses java's getSimpleName method (turned into simple_name by jruby)
to get just the class name without the java package name.
- because it is using OTrunk reflection, the code works on properties
which have types as opposed to methods with return values or with
arguments. This is a better way of dealing with things if you are
trying to figure out what can and cannot go into otml files.
- you will see at least one warning printed to the console about an
invalid field (property). This indicates a class that should be
fixed. Also with the logging stuff in place that Aaron setup we can
route this message through the log system. That way you could disable
it if you needed to.
Scott