Bonjour à tous,
Je plante depuis 2 semaines sur un problème et je commence à me demander si c'est moi qui devient fou.

En effet, je développe actuellement une application dans laquelle j'expose des services REST en utilisant le Framework Apache-CXF, couplé à Spring. La construction du projet se fait avec maven 3 et le plugin enunciate.

Mon problème est le suivant, lorsque j'invoque l'opération de filtre de mon service REST, j'obtiens l'erreur suivante:

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
48
49
 
Status : 500
Headers : 
Date : Tue, 13 Dec 2011 10:54:47 GMT
Content-Length : 155
Content-Type : text/plain
Server : Jetty(8.0.0.v20110901)
Error message : 
Parameter Class com.ai.pis.dao.tools.IntervalDateTime has no constructor with single String parameter, static valueOf(String) or fromString(String) methods
 
	at org.apache.cxf.jaxrs.client.ClientProxyImpl.checkResponse(ClientProxyImpl.java:233)
	at org.apache.cxf.jaxrs.client.ClientProxyImpl.handleResponse(ClientProxyImpl.java:453)
	at org.apache.cxf.jaxrs.client.ClientProxyImpl.doChainedInvocation(ClientProxyImpl.java:445)
	at org.apache.cxf.jaxrs.client.ClientProxyImpl.invoke(ClientProxyImpl.java:177)
	at $Proxy27.filterContracts(Unknown Source)
	at com.ai.pis.garbage.client.ContractManagerRESTTestCaseIT.testFilterContracts(ContractManagerRESTTestCaseIT.java:74)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
	at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:59)
	at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:120)
	at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:103)
	at org.apache.maven.surefire.Surefire.run(Surefire.java:169)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:350)
	at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1021)
Pour fixer les idées, voici respectivement, l'interface Spring du service, son implémentation, ainsi que la classe qui pose problème et qui est annotée avec un Adaptateur de Type JAXB

Interface du service
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
@Produces( { "application/json", "application/xml" } )
@Path( "/contracts" )
public interface ContractManager
{
    
    /**
     * Méthode de filtre des contrats de collecte de déchets
     * @param numero Numéro du contrat
     * @param codeCollecteur Code du collecteur
     * @param intervalCreation IntervalDateTime de la date de création
     * @param intervalEffet Intervalle de la date d'effet
     * @param intervalExpiration Intervalle de la date d'expiration
     * @param firstResult	Index du premier resultat retourne
     * @param maxResult	Nombre maximum d'elements retournes
     * @return	Liste des objet trouves
     */
    @GET
    @Path( "/filterContracts" )
    List<Contract> filterContracts(@QueryParam("numero") String numero,
                                   @QueryParam("codeCollecteur") String codeCollecteur,
                                   @QueryParam("intervalCreation") IntervalDateTime intervalCreation,
                                   @QueryParam("intervalEffet") IntervalDateTime intervalEffet,
                                   @QueryParam("intervalExpiration") IntervalDateTime intervalExpiration,
                                   @QueryParam("firstResult") int firstResult,
                                   @QueryParam("maxResult") int maxResult);
}
Implémentation du service
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
 
@Service( "contractManager" )
@Transactional(propagation = Propagation.REQUIRED)
public class ContractManagerImpl implements ContractManager
{
    private ContractDao contractDao;
 
    @Inject
    public void setContractDao( ContractDao contractDao )
    {
        this.contractDao = contractDao;
        super.genericDao = contractDao;
    }
 
 
    @Override
    public List<Contract> filterContracts(String numero, String codeCollecteur, IntervalDateTime intervalCreation, IntervalDateTime intervalEffet, IntervalDateTime intervalExpiration, int firstResult, int maxResult) {
 
        // On retourne le resultat
        return contractDao.filterContracts(numero, codeCollecteur, intervalCreation, intervalEffet, intervalExpiration, firstResult, maxResult);
    }
 
}
La classe IntervalDateTime
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
 
@XmlType(name = "IntervalDateTime", propOrder = {"min", "max"})
@XmlAccessorType(XmlAccessType.PROPERTY)
public class IntervalDateTime
{
    /**
     * Valeur minimale de l'Intervalle
     */
    @XmlElement
    @XmlJavaTypeAdapter(DateTimeXmlAdapter.class)
    private DateTime min;
 
    /**
     * Valeur Maximale de l'Intervalle
     */
    @XmlElement
    @XmlJavaTypeAdapter(DateTimeXmlAdapter.class)
    private DateTime max;
 
    /**
     * Constructeur par defaut
     */
    public IntervalDateTime()
    {
    }
 
    /**
     * Constructeur avec initialisation des valeurs
     *
     * @param min Valeur minimale de l'Intervalle
     * @param max Valeur Maximale de l'Intervalle
     */
    public IntervalDateTime( DateTime min, DateTime max )
    {
        this.min = min;
        this.max = max;
    }
 
    /**
     * M�thode d'Obtention de la Valeur minimale de l'Intervalle
     *
     * @return Valeur minimale de l'Intervalle
     */
    public DateTime getMin()
    {
        return min;
    }
 
    /**
     * M�thode de mise � jour de la Valeur minimale de l'Intervalle
     *
     * @param min Valeur minimale de l'Intervalle
     */
    public void setMin( DateTime min )
    {
        this.min = min;
    }
 
    /**
     * M�thode d'Obtention de la Valeur Maximale de l'Intervalle
     *
     * @return Valeur Maximale de l'Intervalle
     */
    public DateTime getMax()
    {
        return max;
    }
 
    /**
     * M�thode de mise � jour de la Valeur Maximale de l'Intervalle
     *
     * @param max Valeur Maximale de l'Intervalle
     */
    public void setMax( DateTime max )
    {
        this.max = max;
    }
 
    /**
     * Méthode de construction d'un intervalle de Date à partir de deux Dates
     *
     * @param begin Date de debut
     * @param end   Date de fin
     * @return Intervalle de DateTime
     */
    public static IntervalDateTime buildInstance( Date begin, Date end )
    {
 
        // DateTime de debut
        DateTime borneInf = null;
 
        // DateTime de fin
        DateTime borneSup = null;
 
        // Si La date de début est non nulle
        if ( begin != null )
        {
            borneInf = new DateTime( begin.getTime() );
        }
 
        // Si la Date de fin est non nulle
        if ( end != null )
        {
            borneSup = new DateTime( end.getTime() );
        }
 
        // On retourne l'intervalle
        return new IntervalDateTime( borneInf, borneSup );
 
    }
}
Et voici le code de l'daptateur
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
 
package com.dattek.pis.xml.bind;
 
import org.joda.time.DateTime;
 
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import java.util.Date;
 
 
@XmlTransient
public class DateTimeXmlAdapter
        extends XmlAdapter<Date, DateTime>
{
    public DateTime unmarshal( Date date )
            throws Exception
    {
        return new DateTime( date.getTime() );
    }
 
    public Date marshal( DateTime dateTime )
            throws Exception
    {
        return new Date( dateTime.getMillis() );
    }
}
J'ai malheureusement l'impression que l'adaptateur de type et même JAXB sont ignorés (vu que lors de l'invocation on recherche un constructeur précis ou une méthode précise prenant une chaîne de caractère au lieu de désérialiser en utilisant JAXB). Le problème vient-il de CXF? parce que avec Jersey ce problème ne se pose pas. Ya t-il une autre manière de préciser un adaptateur de type JAXB lorsqu'on utilise Apache-CXF ou encore enunciate?