Return-Path: Delivered-To: apmail-activemq-camel-user-archive@locus.apache.org Received: (qmail 68808 invoked from network); 23 Dec 2008 10:12:35 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 23 Dec 2008 10:12:35 -0000 Received: (qmail 3997 invoked by uid 500); 23 Dec 2008 10:12:34 -0000 Delivered-To: apmail-activemq-camel-user-archive@activemq.apache.org Received: (qmail 3980 invoked by uid 500); 23 Dec 2008 10:12:34 -0000 Mailing-List: contact camel-user-help@activemq.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: camel-user@activemq.apache.org Delivered-To: mailing list camel-user@activemq.apache.org Received: (qmail 3969 invoked by uid 99); 23 Dec 2008 10:12:34 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 23 Dec 2008 02:12:34 -0800 X-ASF-Spam-Status: No, hits=-0.0 required=10.0 tests=SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (athena.apache.org: domain of james.strachan@gmail.com designates 209.85.218.15 as permitted sender) Received: from [209.85.218.15] (HELO mail-bw0-f15.google.com) (209.85.218.15) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 23 Dec 2008 10:12:25 +0000 Received: by bwz8 with SMTP id 8so8565818bwz.14 for ; Tue, 23 Dec 2008 02:12:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:message-id:date:from:to :subject:in-reply-to:mime-version:content-type :content-transfer-encoding:content-disposition:references; bh=PpI00wAHlbe305QtjQDm3RQAD1g7JQGn09J6BkY1/C4=; b=KI1/gmthWmRQ7PrQ5Awrhx5TTVFt4isFGo6oKby2PB1EXaODs0K34Dn1S/zsfOfe9J PCbE9H7XcFgd/QxwSBJTIRq6pMh+Gke7FOYcVymHDXoQ7IxDujHcU2ZXE1Armuf+XvpO WdYJ/ts5jKD3/1dDNYKYnu68Mo2qDiKj56uVI= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:date:from:to:subject:in-reply-to:mime-version :content-type:content-transfer-encoding:content-disposition :references; b=VS7O1++WM8FQiemjI6DEs3aRioDxMPe4nC+aogwPl4sjh74TKX0ZnjLPTkTbElnfJ6 Csbkm2S45ObH4U7QDfCO/vwa0iTdPnJnJ9bsb0Ur1XN3bZeDD+cghNnjl4+PwBK4n+V0 k9jBLHsSu2RgoV725zO46qfZsDCoGKoFl1T3I= Received: by 10.223.113.136 with SMTP id a8mr5809891faq.76.1230027122773; Tue, 23 Dec 2008 02:12:02 -0800 (PST) Received: by 10.223.108.209 with HTTP; Tue, 23 Dec 2008 02:12:02 -0800 (PST) Message-ID: Date: Tue, 23 Dec 2008 10:12:02 +0000 From: "James Strachan" To: camel-user@activemq.apache.org Subject: Re: Advise on @Annotation & Reflection !! In-Reply-To: <21141803.post@talk.nabble.com> MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Content-Disposition: inline References: <21141422.post@talk.nabble.com> <21141803.post@talk.nabble.com> X-Virus-Checked: Checked by ClamAV on apache.org 2008/12/23 cmoulliard : > > > > James.Strachan wrote: >> >> 2008/12/23 cmoulliard : >>> >>> 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/