# sui4j和sui-java-sdk合并讨论 ## 差异对比 | 模块 | Sui4j | sui-java-sdk |探讨| | -------- | -------- | -------- |--------| | build tool | gradle | maven | 两种工具都很常见,目前sui4j增加了checkstyle,spotless,jacoco等提高代码风格,质量的工具插件,合并时可能会有不少代码不符合风格需要改动,但是不难| | json-rpc | 基于OkHttp自己实现 | 复制的https://github.com/starcoinorg/starcoin-java/tree/main/src/main/java代码 |此处如果作为SDK,个人觉得自己实现更好点,减少不必要的外部依赖;因为这块底层实现不同,存在合并问题| | json | 通过接口隐藏了实际使用的序列化库(目前使用Gson) | 直接使用Jackson |此作为SDK我觉得这里不直接把具体的序列化库暴露给用户比较好;因为这块底层使用库也不同,存在合并问题| | websocket | 基于OkHttp自己实现 | 直接使用web3j的方法 |同json-rpc个人觉得自己实现更好,减少不必要的外部依赖;这块实现不同,存在合并问题| | 接口设计 | 异步接口 | 同步接口 |这块存在合并问题| ## 构建工具 使用 Gradle 还是 Maven 我感觉问题都不大,因为我们做的东西是项目结构上比较简单的“类库”项目,不需要太复杂的构建管理。 ## HTTP Client 其实我从 Starcoin Java SDK 移过来的 JSON RPC Client 的代码实现内部也是使用了 okHttp 的。只是在 okHttp 至上做了一些封装。 ## JSON 库 如果不是实在没有办法,建议最好是使用 Java 规范的字段/属性命名风格,然后就可以去掉类似的注解了: ```java @SuppressWarnings({"checkstyle:MemberName", "checkstyle:ParameterName"}) ``` 可以把 Jackson 相关的依赖(那些序列化/反序列化的注解)从 RPC 接口使用的类型中剥离出去,使用 Jackson 的 Mixin 机制好像可以做到。把使用 Jackson 序列化和反序列化的那些实现代码做成单独的包。 Jackson 是使用 Spring Boot 开发后端服务时默认使用的 JSON 库,有很多人在开发后端时并不希望再引入另外的 JSON 库(Fast JSON、GSON 等)依赖。 > 同样,对于 HTTP Client 库的使用不同的人其实也有不同的偏好。比如有的人可能会希望使用 Apache HTTP Client 库。所以建议这些都剥离到单独的包里。 ### BCS 另外就是 BCS 的序列化/反序列化(加上交易的签名工具之类?),建议也是单独做成单独的包。因为如果我是做链下的查询服务、Indexer 服务之类,并不需要用到它们。 ### 包划分 所以,是不是可以考虑这么划分包(底层的/被依赖的包排在前面),包名前缀下面先用 xxx 表示(MoveFuns 赞助一下?给我们开发者定期发点”薪水“,我们可以考虑用 MoveFuns 来命名这些包啊:): 1. xxx-rpc-beans(或 xxx-rpc-common?名称待定)包。全部用于 RPC 调用都是 POJO,不引入对特定 JSON 库的依赖。 2. xxx-bcs 包。包含 BCS 序列化/反序列化相关的功能。 3. xxx-jackson 包。包含使用 Jackson 序列化/反序列化的功能。 4. xxx-gson 包。包含使用 GSON 序列化/反序列化的代码。 5. xxx-okhttp(或者叫其他名字?待定)包。使用上面的基础的包实现 Sui4J 目前已有的功能 6. xxx-jackson-rpc (我随便起的名字,待定)包。使用上面的基础包实现我那个 Sui-Java-SDK 目前已有的功能呢。供喜欢 Jackson + okHttp 组合的开发者使用。 后两个包是不是还是抽取出什么公用的基础包来?感觉后面可以慢慢探讨、重构。开始的时候可能这么划分已经够细了。 ### 对静态类型的支持 有一点需要特别提示的就是,我希望在那个 xxx-rpc-beans(名称待定)包里面,保留对我现在大量使用的这样的方法的支持: ```java public <T> SuiMoveObjectResponse<T> getMoveObject(String objectId, SuiObjectDataOptions options, Class<T> objectType) { options.setShowContent(true);// set showContent to true to get the parsed JSON content List<Object> params = new ArrayList<>(); params.add(objectId); params.add(options); JSONRPC2Request jsonrpc2Request = new JSONRPC2Request("sui_getObject", params, System.currentTimeMillis()); try { JSONRPC2Response<SuiMoveObjectResponse<T>> jsonrpc2Response = jsonrpc2Session .sendAndGetParametricTypeResult(jsonrpc2Request, SuiMoveObjectResponse.class, objectType); assertSuccess(jsonrpc2Response); return jsonrpc2Response.getResult(); } catch (JSONRPC2SessionException e) { throw new RuntimeException(e); } } ``` 我感觉在做特定应用的链下查询服务的时候,直接给一个接口,支持获得特定静态对象的结果还是很有用的,没有必要先让 JSON 库反序列化为 Map 然后再让接口使用者自己转为想要的目标静态对象。 这个方法的用法: ```java @Test void testGetMoveObject_getDynamicFields_getDynamicFieldMoveObject_D() throws MalformedURLException, JsonProcessingException { SuiJsonRpcClient client = new SuiJsonRpcClient("https://fullnode.devnet.sui.io/"); SuiMoveObjectResponse<Order> getObjectDataResponse = client.getMoveObject( "0x50dc4c763b4f3df257a4557345bced2097bd0e32ad4200493527bcfdd1192546", new SuiObjectDataOptions(), Order.class ); System.out.println(getObjectDataResponse); Order order = getObjectDataResponse.getData().getContent().getFields(); //... ``` --- 同样,获取事件的时候也是如此: ```java public <F> PaginatedMoveEvents<F> queryMoveEvents(String moveEvent, EventId cursor, int limit, boolean descendingOrder, Class<F> moveEventFieldsType) { List<Object> params = new ArrayList<>(); params.add(new SuiEventFilter.MoveEventType(moveEvent)); params.add(cursor); params.add(limit); params.add(descendingOrder); JSONRPC2Request jsonrpc2Request = new JSONRPC2Request("suix_queryEvents", params, System.currentTimeMillis()); try { JSONRPC2Response<PaginatedMoveEvents<F>> jsonrpc2Response = getJSONRPC2Session() .sendAndGetParametricTypeResult(jsonrpc2Request, PaginatedMoveEvents.class, moveEventFieldsType); assertSuccess(jsonrpc2Response); return jsonrpc2Response.getResult(); } catch (JSONRPC2SessionException e) { throw new RuntimeException(e); } } ```