camel-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "James Strachan" <james.strac...@gmail.com>
Subject Re: Advise on @Annotation & Reflection !!
Date Tue, 23 Dec 2008 10:12:02 GMT
2008/12/23 cmoulliard <cmoulliard@gmail.com>:
>
>
>
> James.Strachan wrote:
>>
>> 2008/12/23 cmoulliard <cmoulliard@gmail.com>:
>>>
>>> Hi,
>>>
>>> I'm currently working on a small prototype to bind CSV data to POJOs
>>> using
>>> annotation. Camel through its component file:/// and dataformat will
>>> provide
>>> me the infrastructure that I need to parse the file content, extract each
>>> CSV record and return an array of String for each record found in a file.
>>>
>>> Remark : A string contains the list of CSV values separated by a comma.
>>>
>>> In order to bind the CSV values to my POJOs, I have created two
>>> annotations
>>> :
>>>
>>> @Retention(RetentionPolicy.RUNTIME)
>>> public @interface CSVRecord {
>>>
>>>        String name(); --> root name of the class handling the content of
>>> a CSV
>>> record
>>>        String separator(); --> separator used to separate CSV data
>>>
>>> }
>>>
>>> @Retention(RetentionPolicy.RUNTIME)
>>> public @interface CSVField {
>>>
>>>        int pos(); --> key indicating the position of the CSV data in the
>>> CSV
>>> record
>>>        String name(); --> key assigned to the column name of a CSV field
>>>
>>> }
>>>
>>> Here is an example of a POJO (= Model) using these annotations :
>>>
>>> @CSVRecord(separator =",", name = "OrderModel")
>>> public class OrderModel {
>>>
>>>        @CSVField(name = "Number", pos = 0)
>>>        String orderNr;
>>>
>>>        @CSVField(name = "Client Number", pos = 1)
>>>        String clientNr;
>>>
>>>        @CSVField(name = "ISIN", pos = 2)
>>>        String ISIN_Code;
>>>
>>>        @CSVField(name = "Name", pos = 3)
>>>        String Instrument_Name;
>>>
>>>        @CSVField(name = "Quantity", pos = 4)
>>>        String Quantity;
>>>
>>>        @CSVField(name = "Cur", pos = 5)
>>>        String Currency;
>>
>> Minor point - but you could use more defaults in that if you like.
>> e.g. default "," if its not specified and maybe default the name to be
>> the name of the field if its not specified (maybe even default the
>> position?)
>>
>>>> OK. I will check that.
>>
>>
>>> Here is my question ?
>>>
>>> Using reflection (or project ASM in an next step), I'm able at the launch
>>> of
>>> the application to discover all the fields annotated and their
>>> parameters.
>>> With this information, I'm able to set the field value with the CSV data
>>> using the following syntax :
>>>
>>>
>>> String[] result = record.split(csv.retrieveSeparator()); --> to retrieve
>>> the
>>> separator assigned to my CSVRecord
>>> ....
>>> field.set(order, result[csvField.pos()]);
>>>
>>> A CSV record can contain one or several classes like :
>>> - Order (with reference to a client, instrument, billing, ...),
>>> - Client,
>>> - Instrument,
>>> - Billing
>>> where annotations have been defined for the fields corresponding to what
>>> we
>>> have in CSV record.
>>>
>>> Remark : In this first prototype implementation, I will only support
>>> mapping
>>> 1-1 between objects
>>>
>>> Questions :
>>>
>>> 1) What is the best to strategy to recursively find all the annotated
>>> fields
>>> defined within the different classes ?
>>
>> Probably keeping a cache of class -> metadata rather like we do with
>> the annotation metadata for bean binding (see BeanInfo /
>> MethodInfoCache in the org.apache.camel.component.bean package).
>>
>>>> OK. I will check Camel code.
>>
>>
>>> 2) Should we have to create a kind of java tree objects to store the
>>> annotated Fields with existing relation between the different classes (=
>>> model) ?
>>>
>>> ex : RootNode = Order, value = list of annotatedFields, childNode =
>>> Client,
>>> childNode = Instrument, ...
>>>
>>> 3) Is there performant java algorythm to read the Java Tree in order to
>>> find
>>> the annotated field corresponding to a key no matter if the field is
>>> defined
>>> in the parent node or any its children ?
>>
>> Not totally sure I follow this last bit. Are you talking about nested
>> CSVs? Or is it you flatten a master/detail type record into a single
>> row of the csv?
>>
>>>> Yes except that we only have a relation 1-1 between the parent class and
>>>> all these children.
>>
>> The internals of JPA providers or JAXB could be useful
>> maybe (though possibly too complex :).
>>
>>>> For sure. I hope that in the future a JCP project will be created to
>>>> handle binding of non XML data (JAnXB) ;-)
>>
>> Given the flat nature of a CSV its gonna be hard walking an arbitrary
>> object graph and mapping it to a row; but I guess for 1-1
>> relationships you could bind nested fields (e.g. fields of Currency in
>> your example) as optional columns in the parent object's row. In this
>> special case though, just walking the field types (for non-primitive
>> types) would do the trick I think? You'd probably only be able to walk
>> one or two levels deep - and just keep track of types you've already
>> walked maybe?
>>
>>>> What do you mean by optional columns in the parent object ? Can you
>>>> provide me an example James ?

By optional I just meant its hard to know how deep a user may/must go.
But since each field (however deeply nested) is gonna have a single
column index, I guess the whole idea of optional columns is bogus :)

I guess we just need to sort things correctly in a kinda priority
order. e.g. if we've class A which has a field of type B which has a
field of type C we'd put the primitive fields of A first, then
primitive types of B then primitive types of C etc.

BTW fixing the column index on an annotation is a good thing (its like
the thing which makes Protocol Buffers from google so cool) - allowing
you to refactor your code and still be able to read CSVs.

-- 
James
-------
http://macstrac.blogspot.com/

Open Source Integration
http://fusesource.com/

Mime
View raw message