[Java] binding objet JAVA -> XML pour Datasource GWT

binding objet JAVA -> XML pour Datasource GWT [Java] - Java - Programmation

Marsh Posté le 26-10-2009 à 15:47:43    

Bonjour,
 
j'ai besoin d'un petit coup de main sur un problème java :
 
En une phrase : Je cherche à présenter à l'utilisateur la structure d'un objet java, c'est à dire chacun de ses champs leurs valeurs (un toString() fera l'affaire :o), et la possiblité de parcourir les types complexes (listes, maps, etc.).
en gros, la vue "Variables" d'Eclipse ;)
 
J'ai des contraintes techniques :

  • objets JAVA (récupéré d'un référentiel tournant sur un jdk1.4)
  • rendu effectué dans un GUI GWT (jdk1.6)
  • mes objets sont assez complexes et leur structure n'est pas connue à l'avance


 
J'entame tout juste ma réflexion... et à première vue, je serai tenté d'aborder le problème sous cet angle :
1) GWT aime bien les datasources en XML... donc je verrai bien GWT manipuler un XML décrivant l'objet que je dois afficher (sous forme : clé=nom de l'attribut, valeur=toString() de l'attribut)
2) Je dois alors trouver une lib java me permettant de générer un XML à la volée à partir d'un objet java passé en paramètre, par introspection des attributs (ou éventuellement utilisation des getters).
 
 
Des idéees ? Des libs à conseiller ?
 
Merci d'avance :jap:


Message édité par cartemere le 26-10-2009 à 17:23:05
Reply

Marsh Posté le 26-10-2009 à 15:47:43   

Reply

Marsh Posté le 26-10-2009 à 16:01:54    

xstream, mais ca ne fonctionnera que coté serveur


---------------
Light is right
Reply

Marsh Posté le 26-10-2009 à 16:10:01    

nerisson a écrit :

xstream, mais ca ne fonctionnera que coté serveur


le fait que ça tourne coté serveur ne pose pas de souci... au contraire même :
 
La manip va nécessiter un appel coté serveur pour récupérer l'objet java complet, donc tant qu'à faire autant que la transco java->xml soit réalisée coté serveur. :jap:
 
merci en tout cas, je creuse de ce coté ;)

Reply

Marsh Posté le 26-10-2009 à 20:22:22    

XStream est pas mal, j'ai aussi utilisé JAXB 2 (inclus dans J2EE) et ça fonctionne très bien aussi.

Reply

Marsh Posté le 27-10-2009 à 09:20:57    

OK merci, j'ai commencé à regarder du coté de XStream :
 
C'est pas mal effectivement, et ça permet de ressortir assez facilement l'arboresence d'un objet java sous forme de XML.
 
Là par contre, je me heurte deux limitations de GWT :
 
1) le XML en entrée des grilles n'est pas un XML "standard" (avec n niveaux) imbriqués, mais un XML "à plat" avec pour chaque objet une foreign key vers son objet parent.
 

Code :
  1. <List>
  2. <employee>
  3.   <EmployeeId>4</EmployeeId>
  4.   <ReportsTo>1</ReportsTo>
  5.   <Name>Charles Madigen</Name>
  6.   <Job>Chief Operating Officer</Job>
  7.   <Phone>x10962</Phone>
  8.   <Email>cmadigan@server.com</Email>
  9.   <OrgUnit>Management</OrgUnit>
  10.   <Salary>26200.00</Salary>
  11.   <Gender>male</Gender>
  12.   <MaritalStatus>married</MaritalStatus>
  13.   <EmployeeType>full time</EmployeeType>
  14.   <EmployeeStatus>active</EmployeeStatus>
  15. </employee>
  16. <employee>
  17.   <EmployeeId>192</EmployeeId>
  18.   <ReportsTo>4</ReportsTo>
  19.   <Name>Ralph Brogan</Name>
  20.   <Job>Mgr Software Client Supp</Job>
  21.   <Phone>x32524</Phone>
  22.   <Email>rbrogan@server.com</Email>
  23.   <OrgUnit>Management</OrgUnit>
  24.   <Salary>13700.00</Salary>
  25.   <Gender>male</Gender>
  26.   <MaritalStatus>married</MaritalStatus>
  27.   <EmployeeType>full time</EmployeeType>
  28.   <EmployeeStatus>active</EmployeeStatus>
  29. </employee>
  30. <employee>
  31.   <EmployeeId>295</EmployeeId>
  32.   <ReportsTo>192</ReportsTo>
  33.   <Name>Bhushan Sambhus</Name>
  34.   <Job>Line Worker</Job>
  35.   <Phone>x12125</Phone>
  36.   <Email>bsambhus@server.com</Email>
  37.   <OrgUnit>Management</OrgUnit>
  38.   <Salary>8300.00</Salary>
  39.   <Gender>female</Gender>
  40.   <MaritalStatus>married</MaritalStatus>
  41.   <EmployeeType>part time</EmployeeType>
  42.   <EmployeeStatus>active</EmployeeStatus>
  43. </employee>
  44. </List>


 
2) GWT s'attend à ce que les champs soient définis explicitement pour pouvoir en effectuer le rendu... ce qui n'est pas mon cas, puisque le XML généré par XStream reprend comme balise les noms des attributs...
 
 
 
Bref, je dois trouver le moyen de convertir le XML de XStream en un XML "GWT compliant"... et c'est pas gagné :/

Reply

Marsh Posté le 27-10-2009 à 22:07:00    

Je n'ai pas tout compris... de 1, tu veux que le XML soit indenté c'est ça? et de 2, qu'entends-tu par "champ défini explicitement"?

Reply

Marsh Posté le 30-04-2010 à 12:15:09    

cbeyls a écrit :

Je n'ai pas tout compris... de 1, tu veux que le XML soit indenté c'est ça? et de 2, qu'entends-tu par "champ défini explicitement"?


Je réponds un peu tard, mais bon :
 
Je veux un XML, mais dont chacune des entrée référence explicitement son "parent".
Concrêtement en reprenant l'exemple précédent, chaque entrée "employee" dispose d'un identifiant unique "employeeId", et référence son parent par "reportsTo".
Cette mise en forme est nécessaire pour que le composant graphique de smartGWT puisse effectuer un rendu sous forme d'arbre.
 
Le tout doit être réalisé de manière dynamique, car je ne connais pas "à priori" l'arborescence d'objets que je sérialise.
 
 
 
 
 
Je m'en suis sorti par le système suivant :
1) je passe par Xstream pour serialiser mon objet java.
2) je récupère le flux XML sérialisé, que j'interprète via un parser XML
3) je passe de manière récursive à travers les nœuds du XML en reconstruisant une collection d'objets "nœud", où j'indique pour chaque nœud :
   - un identifiant unique
   - l'identifiant de son parent
4) je rattache cette collection à mon composant smartGWT
 
 
dans le détail, voici mon code de réinterprétation

Code :
  1. /**
  2.    * transcode a standard object's XML to a specific GWT Compliant XML
  3.    * @param inputXML the input XML String to transcode
  4.    * @param withRoot keep root in result ?
  5.    * @return the GWT compliant XML String
  6.    * @throws DocumentException in case XML input can not be parsed
  7.    */
  8.   public Collection<TreeObject> transcodeBasicXMLtoGWTCompliantTreeNode(String inputXML, boolean withRoot)
  9.       throws DocumentException {
  10.     IndexHandler indexHandler = new IndexHandler();
  11.     // retrieve input document
  12.     Document inputDoc = DocumentHelper.parseText(inputXML);
  13.     Element inputRoot = inputDoc.getRootElement();
  14.     // create output document
  15.     Collection<TreeObject> treeObjects = new ArrayList<TreeObject>();
  16.     // process all subNodes
  17.     if (withRoot) {
  18.       extractNode(inputRoot, treeObjects, indexHandler, 1);
  19.     } else {
  20.       List<Element> subElements = inputRoot.elements();
  21.       for (Element subElement : subElements) {
  22.         extractNode(subElement, treeObjects, indexHandler, 1);
  23.       }
  24.     }
  25.     return treeObjects;
  26.   }
  27.   private void extractNode(Element inputElement, Collection<TreeObject> treeObjects, IndexHandler indexHandler,
  28.       int parentIndex) {
  29.     // process the input Element
  30.     int inputElementIndex = indexHandler.getNextValue();
  31.     String inputElementName = inputElement.getQName().getName();
  32.     boolean inputElementIsText = inputElement.isTextOnly();
  33.     String inputElementText = null;
  34.     if (inputElementIsText) {
  35.       inputElementText = inputElement.getText();
  36.     }
  37.     TreeObject node = new TreeObject();
  38.     node.setId(inputElementIndex);
  39.     node.setParentId(parentIndex);
  40.     node.setName(extractClassName(inputElementName));
  41.     if (inputElementIsText) {
  42.       node.setValue(inputElementText);
  43.     } else {
  44.       // add empty value : contains children
  45.       node.setValue(StringUtils.EMPTY);
  46.     }
  47.     treeObjects.add(node);
  48.     // process all subNodes
  49.     List<Element> subElements = inputElement.elements();
  50.     for (Element subElement : subElements) {
  51.       extractNode(subElement, treeObjects, indexHandler, inputElementIndex);
  52.     }
  53.   }
  54.   private String extractClassName(String fullQualifiedClassName) {
  55.     if (fullQualifiedClassName != null && fullQualifiedClassName.length() > 0) {
  56.       String[] splittedName = fullQualifiedClassName.split("\\." );
  57.       if (splittedName.length > 1) {
  58.         return splittedName[splittedName.length - 1];
  59.       }
  60.     }
  61.     return fullQualifiedClassName;
  62.   }
  63.   /**
  64.    * Private class managing the record's unique identifier.
  65.    */
  66.   private class IndexHandler {
  67.     private int index;
  68.     public IndexHandler() {
  69.       index = 1;
  70.     }
  71.     public int getNextValue() {
  72.       return ++index;
  73.     }
  74.   }


 
 
sachant que mon objet "nœud" est la classe TreeObject :

Code :
  1. /**
  2. * Generic TreeObject representation (for Java object detail view)
  3. */
  4. public class TreeObject implements Serializable {
  5.   /** current node Id */
  6.   private int id;
  7.   /** parent node Id */
  8.   private int parentId;
  9.   /** attribute name */
  10.   private String name;
  11.   /** attribute value */
  12.   private String value;
  13.   public int getId() {
  14.     return id;
  15.   }
  16.   public void setId(int id) {
  17.     this.id = id;
  18.   }
  19.   public int getParentId() {
  20.     return parentId;
  21.   }
  22.   public void setParentId(int parentId) {
  23.     this.parentId = parentId;
  24.   }
  25.   public String getName() {
  26.     return name;
  27.   }
  28.   public void setName(String name) {
  29.     this.name = name;
  30.   }
  31.   public String getValue() {
  32.     return value;
  33.   }
  34.   public void setValue(String value) {
  35.     this.value = value;
  36.   }
  37. }


 
 
 
et enfin, voici comment j'effectue le rendu via smartGWT

Code :
  1. public class DetailDialogFactory {
  2.  
  3.   public static final int DEFAULT_HEIGHT = 600;
  4.  
  5.   public static final int DEFAULT_WIDTH = 600;
  6.  
  7.   public static final int DEFAULT_TOOLBAR_HEIGHT = 40;
  8.  
  9.   /**
  10.    * Build a Dialog holding a TreeGrid, filled with the provided Tree
  11.    * @param detailLines the Tree lines
  12.    * @param dialogTitle the dialog name
  13.    * @param header a {@link DynamicForm} header definition
  14.    */
  15.   public static void displayDetailDialog(Collection<TreeObject> detailLines, String dialogTitle, DynamicForm header) {
  16.    
  17.     // fill dataSource with results :
  18.     Collection<TreeNode> nodes = new ArrayList<TreeNode>();
  19.     for (TreeObject object : detailLines) {
  20.       RPCTreeObjectDataSource.BuildingTreeNode node = new RPCTreeObjectDataSource.BuildingTreeNode();
  21.       node.setId(object.getId());
  22.       node.setName(Integer.toString(object.getId()));
  23.       node.setParent(object.getParentId());
  24.       node.setTitle(object.getName());
  25.       node.setValue(object.getValue());
  26.       nodes.add(node);
  27.     }
  28.     // Instantiate new DataSource
  29.     RPCTreeObjectDataSource dataSource = new RPCTreeObjectDataSource("DataSource" + System.currentTimeMillis(),1, nodes);
  30.    
  31.     // create Treegrid
  32.     final TreeGrid detailTree = new TreeGrid();
  33.     detailTree.setHeight100();
  34.     detailTree.setWidth100();
  35.     // declare fields
  36.     TreeGridField fieldTitle   = new TreeGridField("title", "Title" );
  37.     TreeGridField fieldValue  = new TreeGridField("value", "Value" );
  38.     // attach fields
  39.     detailTree.setFields(fieldTitle, fieldValue);
  40.     detailTree.setAutoFetchData(true);
  41.     detailTree.setAutoFetchDisplayMap(true);
  42.     detailTree.setDataSource(dataSource);
  43.     detailTree.setLoadDataOnDemand(false);
  44.     detailTree.setAlternateRecordStyles(true);
  45.    
  46.     // Instantiate dialog holder
  47.     final Window dialog = new Window();
  48.     dialog.setWidth(DEFAULT_WIDTH);
  49.     dialog.setHeight(DEFAULT_HEIGHT);
  50.     dialog.setTitle(dialogTitle);
  51.     dialog.setIsModal(false);
  52.     dialog.setCanDragReposition(true);
  53.     dialog.setCanDragResize(true);
  54.    
  55.        
  56.     // add expand all Button
  57.     IButton expandButton = new IButton("Expand All" );
  58.     expandButton.setShowDown(true);
  59.     expandButton.setShowRollOver(true);
  60.     expandButton.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
  61.       public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
  62.         detailTree.getData().openAll();
  63.       }
  64.     });
  65.    
  66.     // add collapse all Button
  67.     IButton collapseButton = new IButton("Collapse All" );
  68.     collapseButton.setShowDown(true);
  69.     collapseButton.setShowRollOver(true);
  70.     collapseButton.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
  71.       public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
  72.         if (detailTree.getData() != null ) {
  73.            detailTree.getData().closeAll();
  74.         }
  75.       }
  76.     });
  77.    
  78.     dialog.addCloseClickHandler(new CloseClickHandler() {
  79.       public void onCloseClick(CloseClientEvent event) {
  80.         dialog.destroy();
  81.       }
  82.     });
  83.    
  84.     // main to display
  85.     VLayout mainPanel = new VLayout();
  86.     mainPanel.setWidth100();
  87.     mainPanel.setHeight100();
  88.     mainPanel.setLayoutMargin(5);
  89.     mainPanel.setMembersMargin(10);
  90.     mainPanel.addMember(header);
  91.    
  92.     SectionStack stack = new SectionStack();
  93.     SectionStackSection section = new SectionStackSection("Detail" );
  94.     section.setCanCollapse(true);
  95.     section.setExpanded(true);
  96.     section.setItems(detailTree);
  97.     stack.addSection(section);
  98.     stack.setHeight("*" );
  99.     stack.setWidth100();
  100.     mainPanel.addMember(stack);
  101.    
  102.     HLayout buttonLayout = new HLayout();
  103.     buttonLayout.setMembersMargin(10);
  104.     buttonLayout.setMembers(expandButton, collapseButton);
  105.     buttonLayout.setAutoHeight();
  106.     buttonLayout.setLayoutBottomMargin(5);
  107.     mainPanel.addMember(buttonLayout);
  108.    
  109.     dialog.addItem(mainPanel);
  110.     dialog.show();
  111.   }
  112. }


 
 
 
 
 
 
 
De cette manière, il est possible de représenter sous forme d'arbre n'importe quel objet JAVA (à condition qu'il ne contienne pas de récursivité) en le convertissant en XML via xstream.toXml(object), et en réinterprétant le flux XML :jap:

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed