JavaおよびFlexのWebアプリケーションを考えます。 Blaze DSまたはAMFシリアル化を使用する同様のテクノロジーが通信に使用されます。 サーバー側とクライアント側では、DTO(データ転送オブジェクト)とリモートサービスインターフェイスが明示的または暗黙的に存在します。 このようなアプリケーションでは、問題はクライアントとサーバー間のDTOコードの同期です。 もちろん、アプリケーションがテストで完全にカバーされている場合、テスト中にJavaソースとActionScriptソースの間の同期が外れていることが明らかになりますが、すでにコンパイル時にフィードバックを取得する機会があります。
これを行うには、ビルドするたびにDTOとリモートインターフェイスを生成する必要があります。 サーバーのDTOまたはリモートインターフェイスを変更する場合、クライアントに応じて変更されます。 これにより、テストを待たずに、コンパイル段階ですでに問題を見つけることができます。さらに、テストがソースコードを完全にカバーしていない可能性を排除することは不可能です。
Granite DSの
clear toolkit 、pimento、Gas3など、AS DTOを生成するための多くのライブラリがあります。
Gas3ライブラリは
flexmojosに統合されて
おり 、テンプレートを編集してクラスを生成することができ、より適切に見えます。 さらに例では、このライブラリが使用されます。
DTO生成
DTO生成の例については、Javaクラス
SampleDto
。
public class SampleDto { public String field1; public String field2; public String getField1() { return field1; } public void setField1(String field1) { this.field1 = field1; } public String getField2() { return field2; } public void setField2(String field2) { this.field2 = field2; } }
このクラスをmavenモジュール
git.example.com:jar:jar
ます。
git.example.com:flex:swf
モジュールでActionScriptコードを生成します。
SampleDto.java
からASコードを生成するには、flexmojos設定に次を追加する必要があります。
<plugin> <groupId>org.sonatype.flexmojos</groupId> <artifactId>flexmojos-maven-plugin</artifactId> <version>3.9</version> <extensions>true</extensions> <configuration> <includeJavaClasses> <includeJavaClass>com.example.*</includeJavaClass> </includeJavaClasses> </configuration> <executions> <execution> <id>generate</id> <goals> <goal>generate</goal> </goals> </execution> </executions> </plugin>
生成されたすべてのクラスは、クラス自体と祖先(基本接尾辞付き)の2つの部分で構成されます。 この場合、生成後、
SampleDtoBase
と
SampleDtoBase
を取得し
SampleDtoBase
。 同じ名前のクラスが存在しない場合、メインクラスが生成されます。 祖先は常に生成され、古いファイルがあればそれを上書きします。 すべての追加機能は、もしあればメインクラスにのみ追加する必要があり、その場合、ジェネレーターはそれに触れません。 Baseクラスに新しい動作を追加すると、ジェネレーターはすべてを削除します。
[Bindable] [RemoteClass(alias="com.example.SampleDto")] public class SampleDto extends SampleDtoBase { } [Bindable] public class SampleDtoBase implements IExternalizable { public var _field1:String; public var _field2:String; public function set field1(value:String):void { _field1 = value; } public function get field1():String { return _field1; } public function set field2(value:String):void { _field2 = value; } public function get field2():String { return _field2; } public function readExternal(input:IDataInput):void { _field1 = input.readObject() as String; _field2 = input.readObject() as String; } public function writeExternal(output:IDataOutput):void { output.writeObject(_field1); output.writeObject(_field2); } }
リモートインターフェイス生成
次に、リモートインターフェイスを生成します。 モジュール
git.example.com:jar:jar
javaクラス
SampleService
を作成し、注釈を付けます。
@RemoteDestination(id = "sampleService", channel = "amf") public class SampleService { public final String sampleMethod1() { return "test output"; } public final String getSampleField1(@Param("sampleDto") final SampleDto sampleDto) { return sampleDto.getField1(); } public final String getSampleField2(@Param("sampleDto") final SampleDto sampleDto) { return sampleDto.getField2(); } @IgnoredMethod public final void ignoredMethod() { } }
@RemoteDestination
は、サービスのチャネルとエンドポイント名を記述し、クラスでハングします。
@Param
は、生成されたメソッドにパラメーター名を設定しますが、オプションです。
@IgnoredMethod
は、タグ付きメソッドを無視するようジェネレーターに指示します。
生成には、DTOと同じ設定を使用します。 出力は2つのクラスです。
[RemoteClass(alias="com.example.SampleService")] public class SampleService extends SampleServiceBase { } public class SampleServiceBase extends RemoteObject { private var _initRemote:Boolean = false; private function initRemote():void { destination = "sampleService"; channelSet = new ChannelSet(); channelSet.addChannel(ServerConfig.getChannel("amf")); _initRemote = true; } public function sampleMethod1():void { if (!_initRemote) initRemote(); getOperation("sampleMethod1").send(); } public function getSampleField2(sampleDto:SampleDto):void { if (!_initRemote) initRemote(); getOperation("getSampleField2").send(sampleDto); } public function getSampleField1(sampleDto:SampleDto):void { if (!_initRemote) initRemote(); getOperation("getSampleField1").send(sampleDto); } public function addOperationListener(op:Function, type:String, handler:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void { if (op == this.sampleMethod1) this.getOperation("sampleMethod1").addEventListener(type, handler, useCapture, priority, useWeakReference); if (op == this.getSampleField2) this.getOperation("getSampleField2").addEventListener(type, handler, useCapture, priority, useWeakReference); if (op == this.getSampleField1) this.getOperation("getSampleField1").addEventListener(type, handler, useCapture, priority, useWeakReference); } public function removeOperationListener(op:Function, event:String, handler:Function):void { if (op == this.sampleMethod1) this.getOperation("sampleMethod1").removeEventListener(event, handler); if (op == this.getSampleField2) this.getOperation("getSampleField2").removeEventListener(event, handler); if (op == this.getSampleField1) this.getOperation("getSampleField1").removeEventListener(event, handler); } }
生成テンプレート
Gas3では、生成のためにテンプレートを変更できます。 メソッドにレスポンダーをハングさせることができるように、リモートインターフェイスを生成するためのテンプレートを変更しましょう。 テンプレートはグルーヴィーで大量に書かれているため、記事には記載されていません。希望する方は、この例のリポジトリのテンプレートを
こちらでご覧いただけます 。 テンプレートを変更するには、テンプレートセクションをflexmojos設定に追加します。
<templates> <base-remote-template> ${project.basedir}/src/main/generator-templates/remoteBase.gsp </base-remote-template> </templates>
その結果、次のサービスコードを取得します。
public class SampleServiceBase extends RemoteObject { private static const logger:ILogger = Log.getLogger(getQualifiedClassName(SampleService).replace("::", ".")); private var _initRemote:Boolean = false; public function SampleServiceBase() { super(); } private function initRemote():void { destination = "sampleService"; channelSet = new ChannelSet(); channelSet.addChannel(ServerConfig.getChannel("amf")); _initRemote = true; } public function getSampleField1(sampleDto:SampleDto, responder:IResponder = null):AsyncToken { if (!_initRemote) { initRemote(); } var asyncToken:AsyncToken = getOperation("getSampleField1").send(sampleDto); if (responder) { asyncToken.addResponder(responder); } if (Log.isDebug()) { logger.debug("Method <getSampleField1> invoked with parameters <{0}>", sampleDto); } return asyncToken; } public function sampleMethod1(responder:IResponder = null):AsyncToken { if (!_initRemote) { initRemote(); } var asyncToken:AsyncToken = getOperation("sampleMethod1").send(); if (responder) { asyncToken.addResponder(responder); } if (Log.isDebug()) { logger.debug("Method <sampleMethod1> invoked with parameters "); } return asyncToken; } public function getSampleField2(sampleDto:SampleDto, responder:IResponder = null):AsyncToken { if (!_initRemote) { initRemote(); } var asyncToken:AsyncToken = getOperation("getSampleField2").send(sampleDto); if (responder) { asyncToken.addResponder(responder); } if (Log.isDebug()) { logger.debug("Method <getSampleField2> invoked with parameters <{0}>", sampleDto); } return asyncToken; } public function addOperationListener(op:Function, type:String, handler:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void { if (op == this.getSampleField1) { this.getOperation("getSampleField1").addEventListener(type, handler, useCapture, priority, useWeakReference); } if (op == this.sampleMethod1) { this.getOperation("sampleMethod1").addEventListener(type, handler, useCapture, priority, useWeakReference); } if (op == this.getSampleField2) { this.getOperation("getSampleField2").addEventListener(type, handler, useCapture, priority, useWeakReference); } } public function removeOperationListener(op:Function, event:String, handler:Function):void { if (op == this.getSampleField1) { this.getOperation("getSampleField1").removeEventListener(event, handler); } if (op == this.sampleMethod1) { this.getOperation("sampleMethod1").removeEventListener(event, handler); } if (op == this.getSampleField2) { this.getOperation("getSampleField2").removeEventListener(event, handler); } } }
Gas3では、リモートインターフェースに加えて、Javaインターフェース、通常のBean、JPAエンティティBeanのテンプレートを変更できます。
まとめ
その結果:
- javaとactionscriptコードの不一致について学ぶ機会を得ました。 Javaコードが変更されると、アクションスクリプトが自動的に変更され、古いバージョンのクラスで動作するコードのすべての部分がコンパイルできなくなります。
- AS DTOおよびリモートインターフェイスを手動で生成する必要がなくなりました。
便宜上、これらのエンティティで動作するWebアプリケーションを作成しました。 ソースコードは
こちらにあります 。
素材
追伸:フラッシュ/フレックスの分野の悪い傾向は知っていますが、私の経験は誰かに役立つかもしれません。