jhunters / jprotobuf Goto Github PK
View Code? Open in Web Editor NEWA useful utility library for java programmer using google protobuf
License: Apache License 2.0
A useful utility library for java programmer using google protobuf
License: Apache License 2.0
定义如下:
@protobuf
private List intList;
报错如下:
Class must has default constructor method with no parameters.
原始类型的数组或者list不支持?
演示代码如下:
public class TestError {
private int age;
}
不好意思,问题解决了,请关闭Issues
Gradle怎么使用预编译插件?
使用1.7.4 Jprotobuf
测试新功能 通过 .proto文件生成POJO类
发现如果 proto文件依赖另一个proto文件,生成带注解的POJO类时 就会报错
例如:
package com.base.research;
option java_package = "com.base.research.protobufMsg.test";
option java_outer_classname = "AddressBookProto";
import "person.proto";
message AddressBook {
repeated Person person = 1;
}
是不支持吗?
集合不支持没有构造函数的对象类型,例如List,初始化时报错。
原生的protobuf是可以支持的:repeated int32 xxx = 1;
如题,这种应该对应那种fieldType?
能重载一个Codec.decode(byte[] bb, int offset, int length)方法吗?
一般通信协议前后端使用的proto文件,服务器能直接通过proto生成带注解的POJO吗
由于jprotobuf采用动态编译的技术,所以启动过程中会进行预编译,影响启动时间,maven编译插件实现把动态编译工作提前到编译发布阶段,提升启动性能
jprotobuf项目的测试用例中,好像仅仅 import "si_product_biz_ref.proto",并没有实际使用 依赖的proto文件中定义的message。
怎么支持类似List List 的类型字段?
public class Test
{
@protobuf(fieldType = FieldType.INT32, order = 1, required = false)
private List list;
}
使用IDLGen.getIDL(Test.class);生成的描述文件不对:
message Test{
optional string list=1;
}
应该是repeated啊。。。
public class Empty
{
}
这样一个类是否应该也是合法的?protobuf是允许这样的对象的
不过使用jprotobuf的IDLGen.getIDL(Empty.class)会抛出异常
相比于直接使用protobuf,使用jprotobuf效率上会降低多少?
v1.7.5
最近一次发布版本才出现的.
一个类有10个字段,如果只使用了其中1个字段,其他9个字段 "应该" 不会encode.
public static int computeListSize(int order, List list, FieldType type) {
int size = 0;
if (list == null) {
return size;
}
for (Object object : list) {
size += computeSize(order, object, type, true);
}
if (type != FieldType.OBJECT) {
size += list.size();
}
return size;
}
.......
if (type != FieldType.OBJECT) {
//这里不能直接 += list.size ,因为只有 order < 16 的时候,tag占位才是1,
//应该是 += (list.size * CodedOutputStream.computeTagSize(order))
size += (list.size * CodedOutputStream.computeTagSize(order));
}
将测试用例中 List< String > 字段的 order 改为 >= 16 即可重现
该特征将支持:
public class AddressBookProtosPOJO {
@Protobuf(fieldType = FieldType.OBJECT, order=1, required = false)
public PersonPOJO list;
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "AddressBookProtosPOJO [list=" + list + "]";
}
}
public class PersonPOJO {
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "PersonPOJO [name=" + name + ", id=" + id + ", email=" + email + "]";
}
@Protobuf(fieldType = FieldType.STRING, order=1, required = true)
public String name;
@Protobuf(fieldType = FieldType.INT32, order=2, required = true)
public int id;
@Protobuf(fieldType = FieldType.STRING, order=3, required = false)
public String email;
@Protobuf(fieldType = FieldType.DOUBLE, order=4, required = false)
public Double doubleF;
@Protobuf(fieldType = FieldType.FLOAT, order=5, required = false)
public Float floatF;
@Protobuf(fieldType = FieldType.BYTES, order=6, required = false)
public byte[] bytesF;
@Protobuf(fieldType=FieldType.BOOL, order=7, required=false)
public Boolean boolF;
}
IDLProxyObject should support all field access include private scope field
CodedConstant.computeSize(int order, Object o, FieldType type, boolean list) 方法中
......
} else if (type == FieldType.FIXED32 || type == FieldType.INT32 || type == FieldType.SFIXED32
|| type == FieldType.SINT32 || type == FieldType.UINT32) {
size = CodedOutputStream.computeInt32SizeNoTag(Integer.valueOf(o.toString()));
} else if (type == FieldType.FIXED64 || type == FieldType.INT64 || type == FieldType.SFIXED64
|| type == FieldType.SINT64 || type == FieldType.UINT64) {
size = CodedOutputStream.computeInt64SizeNoTag(Long.valueOf(o.toString()));
}
.......
FieldType.FIXED32,FieldType.SFIXED32 size应该是固定值4
FieldType.FIXED64,FieldType.SFIXED64 size 应该是固定值8
Dynamic compile failed on current class loader
由于开发中使用注解方便了protobuf的开发,但目前这个功能仅对于java,如果要把注释开发功能,导出给其它语言使用,就需要单独编写.proto文件,需要额外的工作,所以加上自动生成.proto文件的功能可以简化这一部分工作
有想法,谢谢分享!!!!
尊重别人的劳动!!!
不支持Map吗
String idl = ProtobufIDLGenerator.getIDL(RequrieRepeatedNumberTypePOJOClass2.class);
System.out.println(idl);
输出错误内容如下
package com.baidu.bjf.remoting.protobuf.simplerepeat;
option java_outer_classname = "RequrieRepeatedNumberTypePOJOClass2$$ByJProtobuf";
message RequrieRepeatedNumberTypePOJOClass2 {
optional int32 list1=1;
}
public class RequrieRepeatedNumberTypePOJOClass2 {
@Protobuf(fieldType = FieldType.INT32, order = 1, required = false)
public List<Integer> list1;
}
单独的测试方法中 没有问题
public static void main(String[] args) {
Codec<UserJProtoBufProtoClass> codec = ProtobufProxy.create(UserJProtoBufProtoClass.class);
System.out.println(codec);
}
但如果在servlet 方法中调用就会抱这个错误
java.lang.ExceptionInInitializerError
at com.baidu.bjf.remoting.protobuf.ProtobufProxy.create(ProtobufProxy.java:201)
at com.baidu.bjf.remoting.protobuf.ProtobufProxy.create(ProtobufProxy.java:106)
at com.rekoe.protobuf.mobule.ProtobufMobule.test(ProtobufMobule.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.nutz.mvc.impl.processor.MethodInvokeProcessor.process(MethodInvokeProcessor.java:25)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at org.nutz.mvc.impl.processor.AdaptorProcessor.process(AdaptorProcessor.java:33)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at org.nutz.mvc.impl.processor.ActionFiltersProcessor.process(ActionFiltersProcessor.java:40)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at org.nutz.mvc.impl.processor.ModuleProcessor.process(ModuleProcessor.java:113)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at org.nutz.mvc.impl.processor.EncodingProcessor.process(EncodingProcessor.java:27)
at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
at org.nutz.mvc.impl.processor.UpdateRequestAttributesProcessor.process(UpdateRequestAttributesProcessor.java:15)
at org.nutz.mvc.impl.NutActionChain.doChain(NutActionChain.java:40)
at org.nutz.mvc.impl.ActionInvoker.invoke(ActionInvoker.java:67)
at org.nutz.mvc.ActionHandler.handle(ActionHandler.java:31)
at org.nutz.mvc.NutFilter.doFilter(NutFilter.java:183)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1002)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NullPointerException
at com.baidu.bjf.remoting.protobuf.utils.compiler.JdkCompiler.<init>(JdkCompiler.java:74)
at com.baidu.bjf.remoting.protobuf.utils.JDKCompilerHelper.<clinit>(JDKCompilerHelper.java:31)
... 37 more
·``````
public class UserJProtoBufProtoClass {
@Protobuf(fieldType = FieldType.INT64, order = 1, required = false)
public Long id;
@Protobuf(fieldType = FieldType.STRING, order = 2, required = false)
public String name;
@Protobuf(fieldType = FieldType.OBJECT, order = 4)
public PhoneNumberJProtoBufProtoClass phone;
public static class PhoneNumberJProtoBufProtoClass {
@Protobuf(fieldType = FieldType.STRING, order = 1, required = true)
public String number;
}
}
在servlet 返回中调用
OutputStream out = resp.getOutputStream();
codec.writeTo(obj, CodedOutputStream.newInstance(out));
返回的数据是空的
但调用客户端是可以得到返回值的
OutputStream out = resp.getOutputStream();
out.write(codec.encode(obj));
是不是codec.writeTo 方法有问题?
嵌套对象的支持是不是弄得太复杂了?
为了支持这个 codec 上多出了3方法
int size(T t)
void writeTo(T t, CodedOutputStream out)
T readFrom(CodedInputStream intput)
直接把对象 encode 然后直接按照 byte[] 处理效果应该是一样的吧?
ProtobufIDLGenerator目前只有getIDL(Class cls)一个public方法,我们还是需要一个这样的方法: getIDL(Class cls,Set<Class> cachedTypes,Set> cachedEnumTypes) 因为有这个方法的话,就可以避免重复生成同一个类的idl;比如A类引用了B类,C类也引用了B类,当生成A的idl后其实已经生成了B的idl,再调用getIDL(Class cls)传入C的时候,又一次生成B, 所以把两个cache作为参数传入还是有意义的。我目前是在我们的项目里修改这个ProtobufIDLGenerator并提供这个getIDL(Class cls,Set<Class> cachedTypes,Set> cachedEnumTypes) 方法的。
该功能可以支持把jprotobuf动态生成的中间代码的类文件输出到指定目录,以方便后续只有jre环境使用jprotobuf的可行性。
使用示例:Codec codec = ProtobufProxy.create(AddressBookProtosPOJO.class, false, new File("D:/"));
会在d盘根目录下生成中间的类文件对象。下次只需要把这个类文件对象加入到classpath中,就不会再执行动态编译过程了
举个例子:
public class Test
{
@protobuf
private List bps;
public List getBps()
{
return bps;
}
public void setBps(List bps)
{
this.bps = bps;
}
}
这个类,调用ProtobufIDLGenerator的getIDL(Test.class,new HashSet<Class>(),new HashSet>(),true);
生成如下idl:
message Test
{
repeated String bps=1;
}
message String {
}
应该生成这样的吧:
message Test
{
repeated string bps=1;
}
现在有个proto文件用
ProtobufIDLProxy.generateSource(fis, new File(source));
方法无法生成pojo文件 请问是不支持还是格式不对?
用原生的是可以生成的
package pkg;
option java_package = "org.nutz.plugins.protobuf.pojo";
option java_outer_classname = "JJFlyProtocol";
message MixedDataTypeTable
{
message BoolKVP
{
required string Key = 1;
required bool Value = 2;
}
message BoolArrayKVP
{
required string Key = 1;
repeated bool Values = 2;
}
message IntKVP
{
required string Key = 1;
required sint64 Value = 2;
}
message IntArrayKVP
{
required string Key = 1;
repeated sint64 Values = 2;
}
message FloatKVP
{
required string Key = 1;
required float Value = 2;
}
message FloatArrayKVP
{
required string Key = 1;
repeated float Values = 2;
}
message StringKVP
{
required string Key = 1;
required string Value = 2;
}
message StringArrayKVP
{
required string Key = 1;
repeated string Values = 2;
}
message MixedDataTypeTableKVP
{
required string Key = 1;
required MixedDataTypeTable Value = 2;
}
message MixedDataTypeTableArrayKVP
{
required string Key = 1;
repeated MixedDataTypeTable Values = 2;
}
repeated BoolKVP BoolKVPs = 1;
repeated BoolArrayKVP BoolArrayKVPs = 2;
repeated IntKVP IntKVPs = 3;
repeated IntArrayKVP IntArrayKVPs = 4;
repeated FloatKVP FloatKVPs = 5;
repeated FloatArrayKVP FloatArrayKVPs = 6;
repeated StringKVP StringKVPs = 7;
repeated StringArrayKVP StringArrayKVPs = 8;
repeated MixedDataTypeTableKVP MixedDataTypeTableKVPs = 9;
repeated MixedDataTypeTableArrayKVP MixedDataTypeTableArrayKVPs = 10;
}
message JJFlyMessageItem
{
required sint64 ID = 1;
required MixedDataTypeTable Value = 2;
}
message JJFlyMessageRequestBody
{
required sint64 BaseProtocolVersion = 1;
optional string AppID = 2;
optional sint64 ProtocolVersion = 3;
optional sint64 AppVersion = 4;
optional sint64 ResVersion = 5;
optional string Language = 6 [default = "en-US"];
optional string DistributionChannel = 7;
optional string SessionID = 8;
optional sint64 SessionSerialNumber = 9;
repeated JJFlyMessageItem JJFlyMessageItems = 15;
}
message JJFlyMessageResponseBody
{
optional string SessionID = 1;
optional sint64 SessionSerialNumber = 2;
repeated JJFlyMessageItem JJFlyMessageItems = 15;
}
jprotobuf-android支持 android设备
com.baidu jprotobuf-android 1.1.1支持直接根据.proto描述文件动态生成protobuf操作对象,这样可以极简化google protobuf的使用,同时针对需要动态根据.proto描述文件进行操作的实现也是非常有用的帮助
要定义一套错误处理,比如我定义一个范型的rpcresponse 对象。
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class RPCResponse<T> {
@Protobuf(required = true)
private int status = RPCResponseUtil.OK_STATUS; // similar to httpStatus
@Protobuf
private T data;
@Protobuf
private Exception exception;
}
其范型T 的对象可以是
@Data
public class EchoInfo {
@Protobuf
public String message;
}
public class EchoRPCServiceImpl {
@ProtobufRPCService(serviceName = "echoRPCService", methodName = "echo")
public RPCResponse<EchoInfo> doEcho(String message) {
RPCResponse<EchoInfo> ret = new RPCResponse();
if (message.equals("hello")) {
throw new UnknownException();
}
if (message.equals("jersey")) {
throw new CustomException();
}
EchoInfo data = new EchoInfo();
data.setMessage(message);
ret.setData(data);
return ret;
}
}
public interface EchoRPCService {
@ProtobufRPC(serviceName = "echoRPCService", onceTalkTimeout = 5000)
RPCResponse<EchoInfo> echo(String message);
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class Exception {
@Protobuf(required = true)
private long timestamp;
@Protobuf
private int status;
@Protobuf(required = true)
private String errorCode;
@Protobuf(required = true)
private String errorMessage;
@Protobuf(required = true)
private String exception;
@Protobuf
private String path;
}
这样处理了, 好像总是报错。
目前不支持范型?
或者有没有更好的方式处理错误呢? 我目前知道的是用继承的方式,一个个属性写在基类里面。
错误堆栈信息
Caused by: java.lang.IllegalArgumentException: Invalid class [java.lang.String] no field use annotation @com.baidu.bjf.remoting.protobuf.annotation.Protobuf at class java.lang.String
at com.baidu.bjf.remoting.protobuf.ProtobufProxy.getCodeGenerator(ProtobufProxy.java:103)
at com.baidu.bjf.remoting.protobuf.ProtobufProxy.doCreate(ProtobufProxy.java:198)
at com.baidu.bjf.remoting.protobuf.ProtobufProxy.create(ProtobufProxy.java:159)
at com.baidu.bjf.remoting.protobuf.ProtobufProxy.create(ProtobufProxy.java:126)
at com.baidu.jprotobuf.pbrpc.server.AnnotationRpcHandler.<init>(AnnotationRpcHandler.java:54)
at com.baidu.jprotobuf.pbrpc.server.RpcServiceRegistry.doCreateRpcHandler(RpcServiceRegistry.java:119)
at com.baidu.jprotobuf.pbrpc.server.RpcServiceRegistry.doRegiterService(RpcServiceRegistry.java:131)
at com.baidu.jprotobuf.pbrpc.server.RpcServiceRegistry.access$000(RpcServiceRegistry.java:41)
at com.baidu.jprotobuf.pbrpc.server.RpcServiceRegistry$1.doWith(RpcServiceRegistry.java:107)
at com.baidu.jprotobuf.pbrpc.utils.ReflectionUtils.doWithMethods(ReflectionUtils.java:64)
at com.baidu.jprotobuf.pbrpc.utils.ReflectionUtils.doWithMethods(ReflectionUtils.java:41)
at com.baidu.jprotobuf.pbrpc.server.RpcServiceRegistry.registerService(RpcServiceRegistry.java:101)
at com.baidu.jprotobuf.pbrpc.transport.RpcServer.registerService(RpcServer.java:172)
好像 如果属性配置了默认值,生成后的Class类没有配置这个值
optional string Language = 6 [default = "en-US"];
原生的会有这个配置
private java.lang.Object language_ = "en-US";
比如说
public EchoInfo<T> { @Protobuf(seeAlso={A.class, B.class, C.class}) T data; }
在使用的时候:
public EchoServiceImpl { @ProtobufRpcService EchoInfo<A> echo(String msg); }
或者干脆连seeAlso都不需要, 直接根据impl中的泛型的的typeInfer拿到具体的type,从而进行序列化反序列化。
版本1.9.8,使用@protobuf方式,序列化反序列化对象效率非常低。
在代码中调用API生成了POJO源代码(非预编译,是动态编译)
Codec simpleListCodec = ProtobufProxy.create(SimpleList.class, true);
public byte[] encode(SimpleList t) throws IOException {
int size = 0;List f_2=null;
if (!CodedConstant.isNull(t.getList())) {
f_2=t.getList();
}if (!CodedConstant.isNull(t.getList())){
size += CodedConstant.computeListSize(2,f_2, FieldType.STRING,true,ProtobufProxy.OUTPUT_PATH.get());
}
if (f_2== null) {
throw new UninitializedMessageException(CodedConstant.asList("list"));
}
final byte[] result = new byte[size];
final CodedOutputStream output = CodedOutputStream.newInstance(result);
writeTo(t, output);
return result;
}
com.baidu.bjf.remoting.protobuf.CodedConstant#computeSize(int, java.lang.Object, com.baidu.bjf.remoting.protobuf.FieldType, boolean, boolean, java.io.File)
public static int computeSize(int order, Object o, FieldType type, boolean list, boolean debug, File path) {
int size = 0;
if (o == null) {
return size;
}
if (type == FieldType.OBJECT) {
Class cls = o.getClass();
Codec target = ProtobufProxy.create(cls, debug, path);
try {
size = target.size(o);
size = size + CodedOutputStream.computeRawVarint32Size(size);
return size + CodedOutputStream.computeTagSize(order);
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
if (type == FieldType.STRING) {
size = CodedOutputStream.computeStringSizeNoTag(String.valueOf(o));
} else if (type == FieldType.BOOL) {
size = CodedOutputStream.computeBoolSizeNoTag(Boolean.valueOf(String.valueOf(o)));
} else if (type == FieldType.BYTES) {
byte[] bb = (byte[]) o;
size = CodedOutputStream.computeBytesSizeNoTag(ByteString.copyFrom(bb));
} else if (type == FieldType.DOUBLE) {
size = CodedOutputStream.computeDoubleSizeNoTag(Double.valueOf(o.toString()));
} else if (type == FieldType.FIXED32 || type == FieldType.INT32 || type == FieldType.SFIXED32
|| type == FieldType.SINT32 || type == FieldType.UINT32) {
size = CodedOutputStream.computeInt32SizeNoTag(Integer.valueOf(o.toString()));
} else if (type == FieldType.FIXED64 || type == FieldType.INT64 || type == FieldType.SFIXED64
|| type == FieldType.SINT64 || type == FieldType.UINT64) {
size = CodedOutputStream.computeInt64SizeNoTag(Long.valueOf(o.toString()));
} else if (type == FieldType.FLOAT) {
size = CodedOutputStream.computeFloatSizeNoTag(Float.valueOf(o.toString()));
} else if (type == FieldType.ENUM) {
if (o instanceof EnumReadable) {
size = CodedOutputStream.computeInt32SizeNoTag(((EnumReadable) o).value());
} else if (o instanceof Enum) {
size = CodedOutputStream.computeInt32SizeNoTag(((Enum) o).ordinal());
}
}
return size;
}
ProtobufProxy.create是没有缓存生成的对象的,每次调用都重新生成。
在协议定义时,字段顺序通常是明确的,使用默认值时如果不小心在中间新加了一个字段,就会造成协议不兼容,是否可以考虑设置必选?
另外,是否可以考虑order不定义的话,忽略该字段?
jprotobuf版本:1.9.4
执行
ProtobufIDLProxy.generateSource(protoFile, srcPath);
抛异常:
Exception in thread "main" java.lang.RuntimeException: Message 'DataStatus' depend on message 'DataInfo.DataVisibility' is missed
at com.baidu.bjf.remoting.protobuf.ProtobufIDLProxy.hasDependency(ProtobufIDLProxy.java:513)
at com.baidu.bjf.remoting.protobuf.ProtobufIDLProxy.createClass(ProtobufIDLProxy.java:419)
proto:
message DataInfo {
enum DataVisibility {
PUBLIC = 1;
PRIVATE = 2;
}
...
}
message DataStatus {
optional DataInfo.DataVisibility visibility = 1;
}
什么时候会正式发布2.X版本
为什么需要在运行使用JdkCompiler,而不直接使用javassist等字节码方式
--------------------------generate protobuf proxy code end--------------------------
Exception in thread "main" java.lang.IllegalStateException: Compilation failed. class: com.flhx.gate.player.bean.PlayerBaseInfo$$JProtoBufClass, diagnostics: [PlayerBaseInfo$$JProtoBufClass.java:101: 错误: 不兼容的类型: java.util.List无法转换为java.util.ArrayList<com.flhx.gate.player.bean.Building>
ret.setBuildings(__list);
^, PlayerBaseInfo$$JProtoBufClass.java:114: 错误: 不兼容的类型: java.util.List无法转换为java.util.ArrayList<com.flhx.gate.player.bean.Resource>
ret.setResources(__list);
^, PlayerBaseInfo$$JProtoBufClass.java:127: 错误: 不兼容的类型: java.util.List无法转换为java.util.ArrayList<com.flhx.gate.player.bean.Item>
ret.setItems(__list);
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.