IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JPA Java Discussion :

Persistance d'un type générique


Sujet :

JPA Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2009
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Service public

    Informations forums :
    Inscription : Août 2009
    Messages : 16
    Par défaut Persistance d'un type générique
    Bonjour,

    Je souhaiterais utiliser les fichiers de mappings (persistence.xml) pour mapper un modèle de données java vers une base SQL.
    Le modèle java est dans une librairie (un jar) et je n'ai pas la possibilité de le modifier (donc pas d'annotation ...)
    Tout se passait assez bien jusqu'à ce que je rencontre le problème suivant.
    Je souhaite faire persister la classe Pixels. Elle contient des attributs de type PositiveInteger, type qui étent NonNegativeInteger lui même étendant la classe générique PrimitiveType.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    public class Pixels extends AbstractOMEModelObject
    {
    	// Property
    	private String id;
     
    	// Property
    	private PositiveInteger sizeT;
     
        ....
    	}
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    public class PositiveInteger extends NonNegativeInteger {
     
      public PositiveInteger(Integer value) {
        super(value);
        if (value == null || value.intValue() < 1) {
          throw new IllegalArgumentException(
              value + " must not be null and positive.");
        }
      }
     
     
      public static PositiveInteger valueOf(String s) {
        return new PositiveInteger(Integer.valueOf(s));
      }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    public class NonNegativeInteger extends PrimitiveType<Integer> {
     
      public NonNegativeInteger(Integer value) {
        super(value);
        if (value == null || value.intValue() < 0) {
          throw new IllegalArgumentException(
              value + " must not be null or non-negative.");
        }
      }
     
      public static NonNegativeInteger valueOf(String s) {
        return new NonNegativeInteger(Integer.valueOf(s));
      }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
     
    public abstract class PrimitiveType<T> {
     
      /** The delegate value. */
      T value;
     
      /**
       * Default constructor.
       * @param value The delegate value to use.
       */
      PrimitiveType(T value) {
        this.value = value;
      }
     
      /**
       * Default constructor.
       * @param value The delegate value to use.
       */
      PrimitiveType() {
      }
     
      /**
       * Retrieves the concrete delegate value.
       * @return See above.
       */
      public T getValue() {
        return value;
      }
     
      /* (non-Javadoc)
       * @see java.lang.Object#toString()
       */
      @Override
      public String toString() {
        return value.toString();
      }
     
      /* (non-Javadoc)
       * @see java.lang.Object#equals(java.lang.Object)
       */
      @Override
      public boolean equals(Object obj) {
        if (obj instanceof PrimitiveType<?>) {
          return value.equals(((PrimitiveType<?>) obj).getValue());
        }
        return value.equals(obj);
      }
    Pour mapper tout ça j'ai écrit le fichier orm.xml suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
     
    <?xml version="1.0" encoding="UTF-8"?>
    <entity-mappings version="2.0" xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd">
    	<persistence-unit-metadata>
    		<persistence-unit-defaults>
    			<access>FIELD</access>
    		</persistence-unit-defaults>
    	</persistence-unit-metadata>
     
    	<mapped-superclass class="ome.xml.model.primitives.NonNegativeInteger"></mapped-superclass>
    	<mapped-superclass class="ome.xml.model.primitives.PrimitiveType">
    		<attributes>
    			<basic name="value"></basic>
    		</attributes>
    	</mapped-superclass>
     
    	<entity class="ome.xml.model.Pixels">
    		<attributes>
    			<id name="id"></id>
    			<basic name="sizeT"><column name="sizeT"/>
    			</basic>
    			<transient name="channels"/>
    			<transient name="binDataBlocks"/>
    			<transient name="tiffDataBlocks"/>
    			<transient name="metadataOnly"/>
    			<transient name="planes"/>
    			<transient name="annotationLinks"/>
                            ...
    		</attributes>
    	</entity>
     
    </entity-mappings>
    J'utilise eclipselink comme implementation.

    Le test suivant fonctionne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    	@Test
    	public void extractMetadata()  {
     
    		Pixels pixels = new Pixels();
    		pixels.setId("toto");
                    pixels.setPositiveIntger (new PositiveInteger(10));
    	        em.persist(pixels)
    	}
    mais évidemment dans la BD, il met un BLOB au lieu d'un entier...

    si je force la définition de la colonne avec un <basic name="sizeT"><column name="sizeT" column-definition="integer"/>

    j'obtient l'exception:


    javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DatabaseException
    Internal Exception: java.sql.SQLException: Incorrect integer value: '\xAC\xED\x00\x05sr\x00(ome.xml.model.primitives.PositiveInteger\xC3\xAD\x83\xD2\xC9\xD2\xDD\x8C\x02\x00\x00xr\x00+ome.xml.model.' for column 'sizeT' at row 1
    Error Code: 1366
    Call: INSERT INTO PIXELS (ID, DIMENSIONORDER, PHYSICALSIZEX, PHYSICALSIZEY, PHYSICALSIZEZ, SIZEC, sizeT, sizeX, SIZEY, SIZEZ, TIMEINCREMENT, TYPE) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    bind => [12 parameters bound]
    Query: InsertObjectQuery(ome.xml.model.Pixels@320b34b1)
    at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commitInternal(EntityTransactionImpl.java:102)
    ...

    quelqu'un connait-il un moyen de faire persister cette colonne avec un type entier, sans toucher au code java bien sûr ?

  2. #2
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2011
    Messages
    10
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Vendée (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2011
    Messages : 10
    Par défaut
    Bonjour,

    J'ai constaté un problème similaire avec des Embedded entity et l'implémentation OpenJPA . En ce qui nous concerne, nous avons créé un ticket sur le JIRA d'OpenJPA compagné d'un test unitaire. Vu que la soumission date de la semaine dernière, il n'y a pas encore eu de réponse.

  3. #3
    Membre averti
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2009
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Service public

    Informations forums :
    Inscription : Août 2009
    Messages : 16
    Par défaut
    Bonjour,
    J'ai trouvé une solution en utilisant l'annotation 'convert' de eclipselink. Je ne pense pas que ce soit disponible sur OpenJPA vu que ça ne fait pas partie de la spécification.

    Le principe est de déclarer une classe implémentant l'interface Converter d'eclipselink. La méthode convertDataValueToObjectValue prend en entré la donnée avec le type qui vient de la base de données et renvoie le type Java. Et la méthode convertObjectValueToDataValue fait l'inverse.

    Dans mon cas ça donne ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
     
    import ome.xml.model.primitives.PositiveInteger;
     
    import org.eclipse.persistence.mappings.DatabaseMapping;
    import org.eclipse.persistence.mappings.converters.Converter;
    import org.eclipse.persistence.sessions.Session;
     
    public class PositiveIntegerConverter implements Converter{
     
    	@Override
    	public Object convertDataValueToObjectValue(Object arg0, Session arg1) {
    		PositiveInteger integer = new PositiveInteger((Integer)arg0);
    		return integer;
    	}
     
    	@Override
    	public Object convertObjectValueToDataValue(Object arg0, Session arg1) {
    		if (arg0 == null) return 0;
    		Integer integer = new Integer(((PositiveInteger)arg0).getValue());
    		return integer;
    	}
     
    	@Override
    	public void initialize(DatabaseMapping arg0, Session arg1) {
    		// TODO Auto-generated method stub
     
    	}
     
    	@Override
    	public boolean isMutable() {
    		// TODO Auto-generated method stub
    		return false;
    	}
    }
    Au niveau du fichier orm.xml, on déclare un converter et on applique convert au niveau de chaque champs.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
     
    <?xml version="1.0" encoding="UTF-8"?>
    <entity-mappings version="2.0" xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd">
    	<persistence-unit-metadata>
    		<persistence-unit-defaults>
    			<access>FIELD</access>
    		</persistence-unit-defaults>
    	</persistence-unit-metadata>
     
    	<converter name="PositiveIntegerConverter" class="fr.cnrs.mri.wide.ome.converter.PositiveIntegerConverter"/>
     
    	<mapped-superclass class="ome.xml.model.primitives.NonNegativeInteger"></mapped-superclass>
    	<mapped-superclass class="ome.xml.model.primitives.PrimitiveType">
    		<attributes>
    			<basic name="value"></basic>
    		</attributes>
    	</mapped-superclass>
     
    	<entity class="ome.xml.model.Pixels">
    		<table name="pixels"/>
    		<attributes>
    			<id name="id"><column name="id"/></id>
    			<basic name="dimensionOrder">
    				<column name="dimensionOrder"/>
    			</basic>
    			<basic name="sizeT" fetch="EAGER">
    				<convert>PositiveIntegerConverter</convert>
    				<column name="sizeT"/>
    			</basic>
    			<basic name="sizeX">
    				<convert>PositiveIntegerConverter</convert>
    				<column name="sizeX"/>
    			</basic>
    			<basic name="sizeY">
    				<convert>PositiveIntegerConverter</convert>
    				<column name="sizeY"/>
    			</basic>
                            ...
    		</attributes>
    	</entity>	
    </entity-mappings>
    Et ça marche... c'est à dire que les types de données SQL sont des entiers et plus des BLOB.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [2.0] polymorphisme avec des types générique
    Par mister3957 dans le forum Général Dotnet
    Réponses: 3
    Dernier message: 31/05/2007, 08h11
  2. Type générique paramétré ?
    Par Lebbihi dans le forum Langage
    Réponses: 2
    Dernier message: 15/03/2007, 09h58
  3. [Framework] IOC - Type générique
    Par seawolfm dans le forum Spring
    Réponses: 1
    Dernier message: 06/02/2007, 18h17
  4. Réponses: 12
    Dernier message: 23/09/2006, 12h12
  5. y a-t-il un support de types génériques pour python ?
    Par silverhawk.os dans le forum Général Python
    Réponses: 15
    Dernier message: 24/03/2006, 18h23

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo