Dubbo-js uses RPC to get through node and java.
If we can automatically generate Dubbo service interface definition, parameter conversion, and have automatic completion ability in ide, our development experience will be better.
We will like it.
We divide the whole process into three steps.
There are two meanings.
The main responsibility of a translator is to seamlessly connect with nodejs dubbo.
The main responsibility of the converter is to convert JavaScript code into JS objects in hession.JS format and then communicate with Dubbo service.
Let's look at the ast information for DemoProvider and UserRequest in the example above.
{
"classes": {
"com.alibaba.dubbo.demo.DemoProvider": {
"fields": {},
"isAbstract": true,
"isEnum": false,
"isInterface": true,
"methods": {
"sayHello": {
"formalParams": ["name"],
"isOverride": false,
"params": [
{
"name": "java.lang.String",
"typeArgs": []
}
],
"ret": {
"name": "java.lang.String",
"typeArgs": []
},
"typeParams": []
},
"test": {
"formalParams": [],
"isOverride": false,
"params": [],
"ret": {
"name": "java.lang.Void"
},
"typeParams": []
},
"echo": {
"formalParams": [],
"isOverride": false,
"params": [],
"ret": {
"name": "java.lang.String",
"typeArgs": []
},
"typeParams": []
},
"getUserInfo": {
"formalParams": ["request"],
"isOverride": false,
"params": [
{
"name": "com.alibaba.dubbo.demo.UserRequest",
"typeArgs": []
}
],
"ret": {
"name": "com.alibaba.dubbo.demo.UserResponse",
"typeArgs": []
},
"typeParams": []
}
},
"name": "com.alibaba.dubbo.demo.DemoProvider",
"privateFields": [],
"typeParams": [],
"values": []
},
"com.alibaba.dubbo.demo.UserRequest": {
"fields": {
"name": {
"name": "java.lang.String",
"typeArgs": []
},
"id": {
"name": "java.lang.Integer",
"typeArgs": []
},
"email": {
"name": "java.lang.String",
"typeArgs": []
}
},
"isAbstract": false,
"isEnum": false,
"isInterface": false,
"methods": {
"setName": {
"formalParams": ["name"],
"isOverride": false,
"params": [
{
"name": "java.lang.String",
"typeArgs": []
}
],
"ret": {
"name": "java.lang.Void"
},
"typeParams": []
},
"getName": {
"formalParams": [],
"isOverride": false,
"params": [],
"ret": {
"name": "java.lang.String",
"typeArgs": []
},
"typeParams": []
},
"setEmail": {
"formalParams": ["email"],
"isOverride": false,
"params": [
{
"name": "java.lang.String",
"typeArgs": []
}
],
"ret": {
"name": "java.lang.Void"
},
"typeParams": []
},
"setId": {
"formalParams": ["id"],
"isOverride": false,
"params": [
{
"name": "java.lang.Integer",
"typeArgs": []
}
],
"ret": {
"name": "java.lang.Void"
},
"typeParams": []
},
"getEmail": {
"formalParams": [],
"isOverride": false,
"params": [],
"ret": {
"name": "java.lang.String",
"typeArgs": []
},
"typeParams": []
},
"getId": {
"formalParams": [],
"isOverride": false,
"params": [],
"ret": {
"name": "java.lang.Integer",
"typeArgs": []
},
"typeParams": []
},
"toString": {
"formalParams": [],
"isOverride": false,
"params": [],
"ret": {
"name": "java.lang.String",
"typeArgs": []
},
"typeParams": []
}
},
"name": "com.alibaba.dubbo.demo.UserRequest",
"privateFields": ["id", "name", "email"],
"typeParams": [],
"values": []
},
"com.alibaba.dubbo.demo.UserResponse": {
"fields": {
"status": {
"name": "java.lang.String",
"typeArgs": []
},
"info": {
"name": "java.util.Map",
"typeArgs": [
{
"isWildcard": false,
"type": {
"name": "java.lang.String",
"typeArgs": []
}
},
{
"isWildcard": false,
"type": {
"name": "java.lang.String",
"typeArgs": []
}
}
]
}
},
"isAbstract": false,
"isEnum": false,
"isInterface": false,
"methods": {
"getInfo": {
"formalParams": [],
"isOverride": false,
"params": [],
"ret": {
"name": "java.util.Map",
"typeArgs": [
{
"isWildcard": false,
"type": {
"name": "java.lang.String",
"typeArgs": []
}
},
{
"isWildcard": false,
"type": {
"name": "java.lang.String",
"typeArgs": []
}
}
]
},
"typeParams": []
},
"toString": {
"formalParams": [],
"isOverride": false,
"params": [],
"ret": {
"name": "java.lang.String",
"typeArgs": []
},
"typeParams": []
},
"setInfo": {
"formalParams": ["info"],
"isOverride": false,
"params": [
{
"name": "java.util.Map",
"typeArgs": [
{
"isWildcard": false,
"type": {
"name": "java.lang.String",
"typeArgs": []
}
},
{
"isWildcard": false,
"type": {
"name": "java.lang.String",
"typeArgs": []
}
}
]
}
],
"ret": {
"name": "java.lang.Void"
},
"typeParams": []
},
"getStatus": {
"formalParams": [],
"isOverride": false,
"params": [],
"ret": {
"name": "java.lang.String",
"typeArgs": []
},
"typeParams": []
},
"setStatus": {
"formalParams": ["status"],
"isOverride": false,
"params": [
{
"name": "java.lang.String",
"typeArgs": []
}
],
"ret": {
"name": "java.lang.Void"
},
"typeParams": []
}
},
"name": "com.alibaba.dubbo.demo.UserResponse",
"privateFields": ["status", "info"],
"typeParams": [],
"values": []
}
},
"providers": ["com.alibaba.dubbo.demo.DemoProvider"]
}
ArgumentMap is a runtime assistant method whose main responsibility is to trigger data structure transformation.
import {UserRequest} from './UserRequest';
import {UserResponse} from './UserResponse';
import {argumentMap, JavaString} from 'interpret-util';
import {TDubboCallResult, Dubbo} from 'dubbo-js';
export interface IDemoProvider {
sayHello(name: JavaString): TDubboCallResult<string>;
test(): TDubboCallResult<void>;
echo(): TDubboCallResult<string>;
getUserInfo(request: UserRequest): TDubboCallResult<UserResponse>;
}
export const DemoProviderWrapper = {
sayHello: argumentMap,
test: argumentMap,
echo: argumentMap,
getUserInfo: argumentMap,
};
export function DemoProvider(dubbo: Dubbo): IDemoProvider {
return dubbo.proxyService<IDemoProvider>({
dubboInterface: 'com.alibaba.dubbo.demo.DemoProvider',
methods: DemoProviderWrapper,
});
}
export function argumentMap() {
let _arguments = Array.from(arguments);
return _arguments.map(
argumentItem =>
argumentItem.__fields2java
? paramEnhance(argumentItem.__fields2java())
: argumentItem,
);
}
function paramEnhance(javaParams: Array<object> | object) {
if (javaParams instanceof Array) {
for (let i = 0, ilen = javaParams.length; i < ilen; i++) {
let itemParam = javaParams[i];
minusRedundancy(itemParam);
}
} else {
minusRedundancy(javaParams);
}
return javaParams;
}
function minusRedundancy(itemParam: any) {
if (!itemParam) {
return;
}
for (var _key in itemParam.$) {
if (itemParam.$[_key] === null || itemParam.$[_key] === undefined) {
delete itemParam.$[_key];
log('删除 key %s from %j ', itemParam, _key);
}
}
}
There are two ways to use it.
The first approach is very suitable for a small number of Dubbo interfaces, single projects; see hello-egg
The second approach is suitable for large-scale projects, especially multi-project shared interfaces; see Automatic Translation Service