2008/12/23 cmoulliard <cmoulli...@gmail.com>: > > > > James.Strachan wrote: >> >> 2008/12/23 cmoulliard <cmoulli...@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/