2011-12-09 40 views
2

Java 1.6を使用wsimport WebサービスのWSDLからソースを生成しました。要求構造内のフィールドの1つは、WSDLに含まれるXMLスキーマにタイプxs:dateTimeを持ち、生成コードにjavax.xml.datatype.XMLGregorianCalendarと入力します。XMLGregorianCalendarの日付が空の文字列にシリアライズ

soapUIによる手動テストでは、次のシリアル化された値がWebサービスで受け入れられることが確認されています。2011-12-082011-12-08Z以下は受け入れられず、この場合の応答は空の応答(明示的なエラーではない)です:2011-12-08T20:00:002011-12-08T20:00:00-05:00。その場合、サービス自体は.NETで動作します。

私の考えでは、サーバーは完全な日付/時刻を受け入れ、日付のみを拒否する必要がありますが、それ以外の方法は何が起こっているかです。しかし、私は、サーバーの保守担当者が変更に対応することを前提としていません。だから私はクライアントに日付を送るように説得しようとしました。

XMLGregorianCalendarオブジェクトを日付にのみシリアル化するようにクライアントコードを納得させることはできません。実際には、私ができるのはを除いて生成されたコードです。生成されたクライアントコード(wsimportによって生成される)がそれを行うとき、シリアライズされた値は空の文字列であり、サーバーはエラーを正しく返します。私はこれをパケットスニファを使って検証しました。ここで

は、私がリクエストで日付フィールドを作成し、移入しています方法です:

import java.util.Calendar; 
import java.util.GregorianCalendar; 
import javax.xml.datatype.DatatypeConfigurationException; 
import javax.xml.datatype.DatatypeConstants; 
import javax.xml.datatype.DatatypeFactory; 
import javax.xml.datatype.XMLGregorianCalendar; 
import java.util.TimeZone; 
// also import GeneratedRequest from generated packages 

private makeRequest() { 
    GeneratedRequest request; 
    // ... 
    request.setDateField(xmlDayNow(TimeZone.getTimeZone("America/New_York"), 
     6)); // broadcast day starts at 6 am EST 
    // ... 
} 

@XmlSchemaType(name="date") 
private static XMLGregorianCalendar xmlDayNow(TimeZone tz, int localHourStart) 
throws MyException { 
    GregorianCalendar cal = gregorianBroadcastDayNow(tz, localHourStart); 
    XMLGregorianCalendar result; 
    try { 
     result = DatatypeFactory.newInstance().newXMLGregorianCalendarDate(
      cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, 
      cal.get(Calendar.DAY_OF_MONTH), DatatypeConstants.FIELD_UNDEFINED) 
      .normalize(); 
    } catch (DatatypeConfigurationException e) { 
     throw new MyException("XMLGregorianCalendar issue", e); 
    } 
    return result; 
} 

protected static GregorianCalendar gregorianBroadcastDayNow(TimeZone tz, 
     int localHourStart) { 
    GregorianCalendar now = new GregorianCalendar(tz); 
    if (now.get(GregorianCalendar.HOUR_OF_DAY) < localHourStart) { 
     now.add(GregorianCalendar.DAY_OF_MONTH, -1); 
    } 
    return now; 
} 

私の場合でたXMLGregorianCalendarの実装クラスがcom.sun.org.apache.xerces.internal.jaxp.datatype.XMLGregorianCalendarImplです。デバッガで、またはログ出力を追加すると、日付オブジェクトのtoXMLFormat()メソッドを呼び出すと、2011-12-09などの日付のみが返されます。デバッガを使用して日付オブジェクト自体を検査すると、そのフィールドのまたは,dayおよびmonthのフィールドが入力され、その他はnullまたは-2147483648の値がDatatypeConstants.FIELD_UNDEFINEDであることがわかります。私が見つけたすべてのドキュメントとインターネット検索結果によると、私の日付オブジェクトは正しく形成されています。

私はクレイジーですか?サーバーに実際にエラーがありますか?生成されたクライアントコードの拒否は正しい日付だけを送信するのですか?これは正当な "未定義の行動"のケースですか?誤った実装クラスが使用されていますか(とにかく問題になる可能性があります)?私に影響を与えるwsimportに関する既知の問題がありますか?

+0

でしたあなたはGeneratedRequestクラスのリストとXMLスキーマを提供していますか? – korifey

答えて

0

私は認識しませんでした.NET Webサービスの直感的な実装の詳細を見ていました。私の分析では、完全な日付/時刻のシリアル化された文字列を指定すると、サーバーからの空の応答が得られましたが、明示的なエラーは発生しませんでした。

これはサーバー上で、実際には日付/時刻オブジェクトを使用していたものの、すべての時刻を東部標準時の真夜中に強制していたためです。だから、もし私がやっていなかったESTの真夜中までのリクエストで時間を余儀なくされれば、回答には結果だけが集まった。(タイムゾーンが指定されていない場合、サーバーはESTを想定していましたが、まったく時刻がない場合はESTの真夜中が仮定されていました)。

私の場合、解決策は、 Olson America/New_Yorkにタイムゾーンを設定し、要求を作成するときに現地時間を00:00:00に設定します。ここでロイの答えに加えて

3

私は、JAXBの日付変換を自分のデバイスに残してはならないことを発見しました。 wsimportに慣れていませんが、バインディングファイルを指定することはできますか?私はJoda Date/Timeを使用していますが、アイデアは確かです。私binding.xjbにこれを追加しました:

<globalBindings> 
    <serializable /> 
    <javaType name="org.joda.time.DateTime" xmlType="xsd:dateTime" 
     printMethod="someStaticDateConverterClass.printDateIso" 
     parseMethod="someStaticDateConverterClass.parseDateIso" /> 
    <javaType name="org.joda.time.DateTime" xmlType="xs:date" 
     printMethod="someStaticDateConverterClass.printDateYYYYDashMMDashDD" 
     parseMethod="someStaticDateConverterClass.parseDateYYYYDashMMDashDD" /> 
</globalBindings> 

のようなクラスで:

import org.joda.time.DateTime; 
import org.joda.time.format.DateTimeFormat; 
import org.joda.time.format.DateTimeFormatter; 
import org.joda.time.format.ISODateTimeFormat; 

public class someStaticDateConverterClass{ 

private static DateTimeFormatter isoFormat = ISODateTimeFormat.dateTime(); 
private static DateTimeFormatter YYYYDashMMDashDDFormat = DateTimeFormat 
     .forPattern("yyyy-MM-dd"); 
private static DateTimeFormatter YYYYMMDDFormat = DateTimeFormat 
     .forPattern("yyyyMMdd"); 

public static String printDateIso(DateTime value) { 
    return printDate(value, isoFormat); 
} 

public static DateTime parseDateIso(String value) { 
    return parseDate(value, isoFormat); 
} 

public static String printDateYYYYDashMMDashDD(DateTime value) { 
    return printDate(value, YYYYDashMMDashDDFormat); 
} 

public static DateTime parseDateYYYYDashMMDashDD(String value) { 
    return parseDate(value, YYYYDashMMDashDDFormat); 
} 

public static String printDateYYYYMMDD(DateTime value) { 
    return printDate(value, YYYYMMDDFormat); 
} 

public static DateTime parseDateYYYYMMDD(String value) { 
    return parseDate(value, YYYYMMDDFormat); 
} 

private static String printDate(DateTime value, DateTimeFormatter format) { 

    String dateAsStr; 

    if (value != null) { 
     dateAsStr = value.toString(format); 
    } else { 
     dateAsStr = null; 
    } 

    return dateAsStr; 
} 

private static DateTime parseDate(String value, DateTimeFormatter format) { 

    DateTime strAsDate; 

    if (value != null) { 
     strAsDate = format.parseDateTime(value); 
    } else { 
     strAsDate = null; 
    } 
    return strAsDate; 
} 
} 
+0

私はJAXBバインディングを提供するための文書化された方法を見ているように思います。私は解決策に達することができましたが、貢献に感謝します。 – wberry

0

は、MavenのCXFでのApache CXF codegenを設定

/resources/binding.jxbのための有効なバインディングファイルでのpom.xml内部

<?xml version="1.0" encoding="UTF-8"?> 
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" 
    jaxb:extensionBindingPrefixes="xjc" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" 
    xmlns="ns" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    jaxb:version="2.1"> 

    <jaxb:globalBindings> 
    <jaxb:serializable /> 
    <jaxb:javaType name="org.joda.time.DateTime" xmlType="xsd:dateTime" 
     printMethod="package.converters.StaticXmlDateConverter.printDateIso" 
     parseMethod="package.converters.StaticXmlDateConverter.parseDateIso" /> 
    <jaxb:javaType name="org.joda.time.DateTime" xmlType="xsd:date" 
     printMethod="package.converters.StaticXmlDateConverter.printDateYYYYDashMMDashDD" 
     parseMethod="package.converters.StaticXmlDateConverter.parseDateYYYYDashMMDashDD" /> 
     </jaxb:globalBindings> 
</jaxb:bindings> 

 <plugin> 
       <groupId>org.apache.cxf</groupId> 
       <artifactId>cxf-codegen-plugin</artifactId> 
       <version>3.1.6</version> 
       <executions> 
        <execution> 
         <id>generate-sources-0001</id> 
         <phase>generate-sources</phase> 
         <configuration> 
          <defaultOptions> 
           <frontEnd>jaxws21</frontEnd> 
          </defaultOptions> 
          <sourceRoot>${project.build.directory}/generated/</sourceRoot> 
          <wsdlOptions> 
           <wsdlOption> 
            <wsdl>${basedir}/src/main/resources/service.wsdl</wsdl> 
            <wsdlLocation> 
             http://someprovider.com/services/actualservice.asmx?WSDL 
            </wsdlLocation> 
            <bindingFiles> 
             <bindingFile>${basedir}/src/main/resources/binding.xjb</bindingFile> 
            </bindingFiles> 
            <extraargs> 
             <extraarg>-client</extraarg> 
             <extraarg>-verbose</extraarg> 
            </extraargs> 
           </wsdlOption> 
          </wsdlOptions> 

         </configuration> 
         <goals> 
          <goal>wsdl2java</goal> 
         </goals> 
        </execution> 
       </executions> 
      <dependencies> 
       <dependency> 
        <groupId>org.jvnet.jaxb2_commons</groupId> 
        <artifactId>jaxb2-basics-annotate</artifactId> 
        <version>1.0.2</version> 
       </dependency> 
      </dependencies> 
     </plugin> 
関連する問題