<|start_filename|>fidl/example/android/fidlprocessor/src/main/java/com/infinateloop/fidlprocessor/FIDLAnnotationProcessor.java<|end_filename|>
package com.infinateloop.fidlprocessor;

import com.infinateloop.fidl.annotation.FIDL;
import com.jsoniter.output.JsonStream;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.model.FilteredMemberList;

import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.tools.FileObject;
import javax.tools.StandardLocation;

public class FIDLAnnotationProcessor extends AbstractProcessor {

    private Filer mFiler;
    private Elements mElements;
    private Map<String, AnnotatedClass> mAnnotatedClassMap = new HashMap<>();

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        mElements = processingEnv.getElementUtils();
        mFiler = processingEnv.getFiler();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        mAnnotatedClassMap.clear();
        Set<Type> collections = new HashSet<>();
        for (Element element : roundEnv.getElementsAnnotatedWith(FIDL.class)) {
            if (element.getKind() == ElementKind.INTERFACE) {
                collectAnnotatedClass(element, collections);
            } else {
                throw new IllegalArgumentException(String.format("FIDL annotation supports only interface, so % is not valid", element.getSimpleName()));
            }
        }

        for (AnnotatedClass annotatedClass : mAnnotatedClassMap.values()) {
            try {
                // generate FIDL json
                annotatedClass.generateFidlStubClass().writeTo(mFiler);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        // generate Classes json
        List<FidlStructure.Class> classes = new ArrayList<>();
        for (Type type : collections) {
            classes.add(new FidlStructure.Class(type));
        }

        for (FidlStructure.Class clazz : classes) {
            JsonFidlStructure.Class jClazz = JsonFidlStructure.Class.from(clazz);
            FileObject fileObject = null;
            try {
                fileObject = mFiler.createResource(StandardLocation.SOURCE_OUTPUT, "", clazz.type.tsym.getQualifiedName().toString() + ".json");
                Writer writer = fileObject.openWriter();
                writer.write(JsonStream.serialize(jClazz));
                writer.flush();
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return true;
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> types = new LinkedHashSet<>();
        types.add(FIDL.class.getCanonicalName());
        return types;
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    private void collectAnnotatedClass(Element element, Set<Type> typeSet) {
        TypeElement mElement = (TypeElement) element;

        FilteredMemberList members = (FilteredMemberList) mElements.getAllMembers(mElement);
        Iterator<Symbol> iterator = members.iterator();
        List<FidlStructure.Method> methodList = new ArrayList<>();
        while (iterator.hasNext()) {
            Symbol symbol = iterator.next();
            if (!(symbol.type instanceof Type.MethodType) ||
                    symbol.owner.flatName().contentEquals(Object.class.getName())) {
                continue;
            }

            Symbol.MethodSymbol mSymbol = (Symbol.MethodSymbol) symbol;
            List<FidlStructure.Parameter> parameters = new ArrayList<>();
            if (mSymbol.params != null) {
                for (Symbol.VarSymbol var : mSymbol.params) {
                    parameters.add(new FidlStructure.Parameter(var.name.toString(), var.type));
                }
            }
            methodList.add(new FidlStructure.Method(mSymbol.name.toString(), ((Type.MethodType) mSymbol.type).restype, parameters));
        }

        String fullClassName = mElement.getQualifiedName().toString();
        FidlStructure structure = new FidlStructure(fullClassName, methodList);
        AnnotatedClass annotatedClass = mAnnotatedClassMap.get(fullClassName);
        if (annotatedClass == null) {
            annotatedClass = new AnnotatedClass(mElement, mElements, structure);
            mAnnotatedClassMap.put(fullClassName, annotatedClass);

            try {
                FileObject fileObject = mFiler.createResource(StandardLocation.SOURCE_OUTPUT, "", structure.className + ".fidl.json");
                Writer writer = fileObject.openWriter();
                Set<Type> types = structure.getTypes();
                writer.write(JsonStream.serialize(JsonFidlStructure.from(structure)));
                writer.flush();
                writer.close();

                TypeUtils.collectNonBasicTypes(types, typeSet);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}


<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example.bean/Gender.dart<|end_filename|>
enum Gender {
  FEMALE,
  MALE,
}


<|start_filename|>fidl/example/android/app/src/main/java/com/infiniteloop/fidl_example/MainActivity.java<|end_filename|>
package com.infiniteloop.fidl_example;

import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import com.infiniteloop.fidl.FidlChannel;
import com.infiniteloop.fidl_example.bean.AUser;
import com.infiniteloop.fidl_example.bean.Conversation;
import com.infiniteloop.fidl_example.bean.EmptyEnum;
import com.infiniteloop.fidl_example.bean.Gender;
import com.infiniteloop.fidl_example.bean.MessageStatus;
import com.infiniteloop.fidl_example.bean.UiMessage;
import com.infiniteloop.fidl_example.bean.User;
import com.infiniteloop.fidl_example.bean.UserInfo;
import com.infiniteloop.fidl_example.im_sdk.ChatManager;
import com.infiniteloop.fidl_example.im_sdk.ChatService;

import java.util.AbstractCollection;
import java.util.AbstractList;
import java.util.AbstractMap;
import java.util.AbstractQueue;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Queue;
import java.util.Set;
import java.util.Stack;
import java.util.TreeSet;
import java.util.Vector;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;

import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.GeneratedPluginRegistrant;

public class MainActivity extends FlutterActivity {
    @Override
    public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        GeneratedPluginRegistrant.registerWith(flutterEngine);
    }

    private IChatServiceStub chatServiceStub;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        chatServiceStub = new IChatServiceStub() {
            @Override
            public boolean init(User<String> user) {
                ChatManager.init(user);
                ChatManager.Instance().setBinaryMessenger(getFlutterEngine().getDartExecutor());
                startService(new Intent(MainActivity.this, ChatService.class));
                return true;
            }
        };
        FidlChannel.openChannel(getFlutterEngine().getDartExecutor(), chatServiceStub);

        FidlChannel.openChannel(getFlutterEngine().getDartExecutor(), new IUserServiceStub() {
            @Override
            public void initArr0(int[] ids) {

            }

            @Override
            public void initArr1(int[][] ids) {

            }

            @Override
            public void initEnum0(EmptyEnum e) {

            }

            @Override
            public String initEnum1(MessageStatus status) {
                System.out.println(status + " is be callback");
                return "inited";
            }

            @Override
            public void initList0(List<String> ids) {

            }

            @Override
            public void initList1(Collection<String> ids) {

            }

            @Override
            public void initList2(Vector<String> ids) {

            }

            @Override
            public void initList3(AbstractList<String> ids) {

            }

            @Override
            public void initList4(AbstractCollection<String> ids) {

            }

            @Override
            public void initList5(CopyOnWriteArrayList<String> ids) {

            }

            @Override
            public void initList6(LinkedList<String> ids) {

            }

            @Override
            public void initList7(Stack<String> ids) {

            }

            @Override
            public void initList8(Queue ids) {

            }

            @Override
            public void initList9(AbstractQueue<String> ids) {

            }

            @Override
            public void initList10(BlockingQueue ids) {

            }

            @Override
            public void initSet0(Set ids) {

            }

            @Override
            public void initSet1(AbstractSet ids) {

            }

            @Override
            public void initSet2(HashSet<String> ids) {

            }

            @Override
            public void initSet3(CopyOnWriteArraySet ids) {

            }

            @Override
            public void initSet4(TreeSet<String> ids) {

            }

            @Override
            public void initSet5(LinkedHashSet<String> ids) {

            }

            @Override
            public void initMap0(Map<String, String> ids) {

            }

            @Override
            public void initMap1(AbstractMap map) {

            }

            @Override
            public void initMap2(AbstractMap<?, String> map) {

            }

            @Override
            public void initMap3(AbstractMap<?, Object> map) {

            }

            @Override
            public void initMap4(AbstractMap<?, ?> map) {

            }

            @Override
            public void initMap5(HashMap<?, List<HashMap<String, String>>> map) {

            }

            @Override
            public void initMap6(HashMap<String, String> ids) {

            }

            @Override
            public void initMap7(Hashtable<String, String> ids) {

            }

            @Override
            public void initMap8(Properties ids) {

            }

            @Override
            public void initObj0(UserInfo info) {

            }

            @Override
            public void initObj1(User user) {

            }

            @Override
            public void initObj2(AUser user) {

            }

            @Override
            public void initObj3(User<String> user) {

            }

            @Override
            public String initRet0() {
                return "empty";
            }

            @Override
            public boolean initRet1() {
                return false;
            }

            @Override
            public int initRet2() {
                return 0;
            }

            @Override
            public byte initRet3() {
                return 0;
            }

            @Override
            public short initRet4() {
                return 0;
            }

            @Override
            public long initRet5() {
                return 0;
            }

            @Override
            public char initRet6() {
                return 0;
            }

            @Override
            public Boolean initRet7() {
                return false;
            }

            @Override
            public boolean[] initRet8() {
                return new boolean[0];
            }

            @Override
            public Byte initRet9() {
                return 0;
            }

            @Override
            public byte[] initRet10() {
                return new byte[0];
            }

            @Override
            public Short initRet11() {
                return null;
            }

            @Override
            public short[] initRet12() {
                return new short[0];
            }

            @Override
            public Long initRet13() {
                return 0L;
            }

            @Override
            public long[] initRet14() {
                return new long[0];
            }

            @Override
            public Character initRet15() {
                return 0;
            }

            @Override
            public char[] initRet16() {
                return new char[0];
            }

            @Override
            public String[] initRet17() {
                return new String[0];
            }

            @Override
            public List<String> initRet18() {
                return new ArrayList<>();
            }

            @Override
            public void init(String name, Integer age, Gender gender, Conversation conversation) {

            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        FidlChannel.closeChannel(chatServiceStub);
        stopService(new Intent(this, ChatService.class));
    }
}


<|start_filename|>fidl/example/android/app/src/main/java/com/infiniteloop/fidl_example/im_sdk/ChatService.java<|end_filename|>
package com.infiniteloop.fidl_example.im_sdk;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;

import com.infiniteloop.fidl.FidlChannel;
import com.infiniteloop.fidl.LogUtils;
import com.infiniteloop.fidl_example.IConversationServiceStub;
import com.infiniteloop.fidl_example.bean.Conversation;
import com.infiniteloop.fidl_example.bean.Message;
import com.infiniteloop.fidl_example.bean.MessageDirection;
import com.infiniteloop.fidl_example.bean.TextMessageContent;
import com.infiniteloop.fidl_example.bean.UiMessage;
import com.infiniteloop.fidl_example.bean.UserInfo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ChatService extends Service {
    private IConversationServiceStub conversationServiceStub;

    private Conversation currentConversation;

    private List<UserInfo> userRepo = Arrays.asList(
            new UserInfo("10", "Amy", 16),
            new UserInfo("11", "Wilson", 18),
            new UserInfo("12", "Lucy", 20)
    );

    private Map<String, List<UiMessage>> messageRepo = new HashMap<String, List<UiMessage>>() {{
        for (UserInfo info : userRepo) {
            List<UiMessage> messages = new ArrayList<>();
            Conversation amyConversation = new Conversation();
            amyConversation.target = info.uid;
            amyConversation.type = Conversation.ConversationType.Single;

            Message message0 = new Message();
            message0.conversation = amyConversation;
            message0.direction = MessageDirection.Receive;
            message0.content = new TextMessageContent("Hi! I'm " + info.name + ", nice to meet you!");
            messages.add(new UiMessage(message0));

            Message message1 = new Message();
            message1.conversation = amyConversation;
            message1.direction = MessageDirection.Send;
            message1.content = new TextMessageContent("Nice to meet you, too!");
            messages.add(new UiMessage(message1));

            put(info.uid, messages);
        }
    }};

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        conversationServiceStub = new IConversationServiceStub() {
            @Override
            public void setupConversation(Conversation conversation) {
                LogUtils.d("setupConversation: " + conversation);
                currentConversation = conversation;
            }

            @Override
            public String getConversationDesc() {
                LogUtils.d("getConversationDesc");
                StringBuilder sb = new StringBuilder("My id: " + ChatManager.getMe().uid + "\n");
                sb.append("My age：").append(ChatManager.getMe().age).append("\n");
                sb.append("My name：").append(ChatManager.getMe().name).append("\n\n");
                if (currentConversation == null) {
                    sb.append("Conversation seems not being initialized!");
                } else {
                    UserInfo userInfo = null;
                    for (UserInfo info : userRepo) {
                        if (info.uid.equals(currentConversation.target)) {
                            userInfo = info;
                            break;
                        }
                    }
                    if (userInfo == null) {
                        sb.append("Partner is not found!");
                    } else {
                        sb.append("Partner's id：").append(userInfo.uid).append("\n");
                        sb.append("Partner's age：").append(userInfo.age).append("\n");
                        sb.append("Partner's name：").append(userInfo.name);
                    }
                }
                LogUtils.d(sb);
                return sb.toString();
            }

            @Override
            public List<UiMessage> getMessages() {
                if (currentConversation == null) {
                    LogUtils.e("Conversation is not initialized!");
                    return new ArrayList<>();
                }
                return messageRepo.get(currentConversation.target);
            }

            @Override
            public void sendMessage(String message) {
                if (currentConversation == null) {
                    LogUtils.e("Conversation is not initialized!");
                    return;
                }
                Message message0 = new Message();
                message0.conversation = currentConversation;
                message0.direction = MessageDirection.Send;
                message0.content = new TextMessageContent(message);
                messageRepo.get(currentConversation.target).add(new UiMessage(message0));
            }

            @Override
            public int getMessageCount() {
                if (currentConversation == null) {
                    return 0;
                }
                return messageRepo.get(currentConversation.target).size();
            }
        };
        FidlChannel.openChannel(ChatManager.Instance().getMessenger(), conversationServiceStub);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        FidlChannel.closeChannel(conversationServiceStub);
    }
}


<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example.bean/Message.g.dart<|end_filename|>
// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'Message.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

Message _$MessageFromJson(Map<String, dynamic> json) {
  return Message()
    ..serverTime = json['serverTime'] as int
    ..messageUid = json['messageUid'] as int
    ..status = _$enumDecodeNullable(_$MessageStatusEnumMap, json['status'])
    ..direction =
        _$enumDecodeNullable(_$MessageDirectionEnumMap, json['direction'])
    ..content = json['content'] == null
        ? null
        : MessageContent.fromJson(json['content'] as Map<String, dynamic>)
    ..toUsers = (json['toUsers'] as List)?.map((e) => e as String)?.toList()
    ..sender = json['sender'] as String
    ..conversation = json['conversation'] == null
        ? null
        : Conversation.fromJson(json['conversation'] as Map<String, dynamic>)
    ..messageId = json['messageId'] as int;
}

Map<String, dynamic> _$MessageToJson(Message instance) => <String, dynamic>{
      'serverTime': instance.serverTime,
      'messageUid': instance.messageUid,
      'status': _$MessageStatusEnumMap[instance.status],
      'direction': _$MessageDirectionEnumMap[instance.direction],
      'content': instance.content,
      'toUsers': instance.toUsers,
      'sender': instance.sender,
      'conversation': instance.conversation,
      'messageId': instance.messageId,
    };

T _$enumDecode<T>(
  Map<T, dynamic> enumValues,
  dynamic source, {
  T unknownValue,
}) {
  if (source == null) {
    throw ArgumentError('A value must be provided. Supported values: '
        '${enumValues.values.join(', ')}');
  }

  final value = enumValues.entries
      .singleWhere((e) => e.value == source, orElse: () => null)
      ?.key;

  if (value == null && unknownValue == null) {
    throw ArgumentError('`$source` is not one of the supported values: '
        '${enumValues.values.join(', ')}');
  }
  return value ?? unknownValue;
}

T _$enumDecodeNullable<T>(
  Map<T, dynamic> enumValues,
  dynamic source, {
  T unknownValue,
}) {
  if (source == null) {
    return null;
  }
  return _$enumDecode<T>(enumValues, source, unknownValue: unknownValue);
}

const _$MessageStatusEnumMap = {
  MessageStatus.Played: 'Played',
  MessageStatus.Readed: 'Readed',
  MessageStatus.Unread: 'Unread',
  MessageStatus.AllMentioned: 'AllMentioned',
  MessageStatus.Mentioned: 'Mentioned',
  MessageStatus.Send_Failure: 'Send_Failure',
  MessageStatus.Sent: 'Sent',
  MessageStatus.Sending: 'Sending',
};

const _$MessageDirectionEnumMap = {
  MessageDirection.Receive: 'Receive',
  MessageDirection.Send: 'Send',
};


<|start_filename|>fidl/android/src/main/java/com/infiniteloop/fidl/ObjectCodec.java<|end_filename|>
package com.infiniteloop.fidl;

import java.util.List;

public interface ObjectCodec {
    List<byte[]> encode(Object... objects);

    <T> T decode(byte[] input, TypeLiteral<T> type);
}


<|start_filename|>fidl/example/android/app/src/main/java/com/infiniteloop/fidl_example/im_sdk/ChatManager.java<|end_filename|>
package com.infiniteloop.fidl_example.im_sdk;

import com.infiniteloop.fidl_example.bean.User;

import io.flutter.plugin.common.BinaryMessenger;

public class ChatManager {
    private static ChatManager INST;

    public static void init(User<String> user) {
        if (INST != null) {
            return;
        }
        INST = new ChatManager(user);
    }

    private User<String> me;
    private BinaryMessenger messenger;

    private ChatManager(User<String> me) {
        this.me = me;
    }

    public static ChatManager Instance() throws NullPointerException {
        if (INST == null) {
            throw new NullPointerException("ChatManager is not initialized!");
        }
        return INST;
    }

    public static User<String> getMe() {
        return Instance().me;
    }

    public void setBinaryMessenger(BinaryMessenger messenger) {
        this.messenger = messenger;
    }

    public BinaryMessenger getMessenger() {
        return messenger;
    }
}


<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example.bean/MessageContent.dart<|end_filename|>
import 'package:json_annotation/json_annotation.dart';

part 'MessageContent.g.dart';

@JsonSerializable()
class MessageContent extends Object {
  MessageContent();

  String pushContent;
  String extra;
  List<String> mentionedTargets;
  int mentionedType;
  
  factory MessageContent.fromJson(Map<String, dynamic> json) => _$MessageContentFromJson(json);

  Map<String, dynamic> toJson() => _$MessageContentToJson(this);
}


<|start_filename|>fidl/android/src/main/java/com/infiniteloop/fidl/FlutterException.java<|end_filename|>
package com.infiniteloop.fidl;

import android.util.Log;

import io.flutter.BuildConfig;

public class FlutterException extends RuntimeException {
  private static final String TAG = "FlutterException#";

  public final String code;
  public final Object details;

  public FlutterException(String code, String message, Object details) {
    super(message);
    if (BuildConfig.DEBUG && code == null) {
      Log.e(TAG, "Parameter code must not be null.");
    }
    this.code = code;
    this.details = details;
  }
}

<|start_filename|>fidl/example/android/app/src/main/java/com/infiniteloop/fidl_example/IConversationService.java<|end_filename|>
package com.infiniteloop.fidl_example;

import com.infinateloop.fidl.annotation.FIDL;
import com.infiniteloop.fidl_example.bean.Conversation;
import com.infiniteloop.fidl_example.bean.UiMessage;

import java.util.List;

@FIDL
public interface IConversationService {
    void setupConversation(Conversation conversation);
    String getConversationDesc();

    List<UiMessage> getMessages();
    void sendMessage(String message);
    int getMessageCount();
}


<|start_filename|>fidl/example/fidl/com.infiniteloop.fidl_example.IUserService.fidl.json<|end_filename|>
{"cls":"com.infiniteloop.fidl_example.IUserService","kind":"fidl","methods":[{"name":"initArr0","returns":"void","parameters":[{"name":"ids","type":"@list(int)"}]},{"name":"initArr1","returns":"void","parameters":[{"name":"ids","type":"@list(@list(int))"}]},{"name":"initEnum0","returns":"void","parameters":[{"name":"e","type":"@enum(com.infiniteloop.fidl_example.bean.EmptyEnum)"}]},{"name":"initEnum1","returns":"String","parameters":[{"name":"status","type":"@enum(com.infiniteloop.fidl_example.bean.MessageStatus)"}]},{"name":"initList0","returns":"void","parameters":[{"name":"ids","type":"@list(String)"}]},{"name":"initList1","returns":"void","parameters":[{"name":"ids","type":"@list(String)"}]},{"name":"initList2","returns":"void","parameters":[{"name":"ids","type":"@list(String)"}]},{"name":"initList3","returns":"void","parameters":[{"name":"ids","type":"@list(String)"}]},{"name":"initList4","returns":"void","parameters":[{"name":"ids","type":"@list(String)"}]},{"name":"initList5","returns":"void","parameters":[{"name":"ids","type":"@list(String)"}]},{"name":"initList6","returns":"void","parameters":[{"name":"ids","type":"@list(String)"}]},{"name":"initList7","returns":"void","parameters":[{"name":"ids","type":"@list(String)"}]},{"name":"initList8","returns":"void","parameters":[{"name":"ids","type":"@list(?)"}]},{"name":"initList9","returns":"void","parameters":[{"name":"ids","type":"@list(String)"}]},{"name":"initList10","returns":"void","parameters":[{"name":"ids","type":"@list(?)"}]},{"name":"initSet0","returns":"void","parameters":[{"name":"ids","type":"@set(?)"}]},{"name":"initSet1","returns":"void","parameters":[{"name":"ids","type":"@set(?)"}]},{"name":"initSet2","returns":"void","parameters":[{"name":"ids","type":"@set(String)"}]},{"name":"initSet3","returns":"void","parameters":[{"name":"ids","type":"@set(?)"}]},{"name":"initSet4","returns":"void","parameters":[{"name":"ids","type":"@set(String)"}]},{"name":"initSet5","returns":"void","parameters":[{"name":"ids","type":"@set(String)"}]},{"name":"initMap0","returns":"void","parameters":[{"name":"ids","type":"@map(String,String)"}]},{"name":"initMap1","returns":"void","parameters":[{"name":"map","type":"@map()"}]},{"name":"initMap2","returns":"void","parameters":[{"name":"map","type":"@map(?,String)"}]},{"name":"initMap3","returns":"void","parameters":[{"name":"map","type":"@map(?,?)"}]},{"name":"initMap4","returns":"void","parameters":[{"name":"map","type":"@map(?,?)"}]},{"name":"initMap5","returns":"void","parameters":[{"name":"map","type":"@map(?,@list(@map(String,String)))"}]},{"name":"initMap6","returns":"void","parameters":[{"name":"ids","type":"@map(String,String)"}]},{"name":"initMap7","returns":"void","parameters":[{"name":"ids","type":"@map(String,String)"}]},{"name":"initMap8","returns":"void","parameters":[{"name":"ids","type":"@map()"}]},{"name":"initObj0","returns":"void","parameters":[{"name":"info","type":"com.infiniteloop.fidl_example.bean.UserInfo"}]},{"name":"initObj1","returns":"void","parameters":[{"name":"user","type":"com.infiniteloop.fidl_example.bean.User"}]},{"name":"initObj2","returns":"void","parameters":[{"name":"user","type":"com.infiniteloop.fidl_example.bean.AUser"}]},{"name":"initObj3","returns":"void","parameters":[{"name":"user","type":"com.infiniteloop.fidl_example.bean.User(String)"}]},{"name":"initRet0","returns":"String","parameters":[]},{"name":"initRet1","returns":"bool","parameters":[]},{"name":"initRet2","returns":"int","parameters":[]},{"name":"initRet3","returns":"byte","parameters":[]},{"name":"initRet4","returns":"short","parameters":[]},{"name":"initRet5","returns":"long","parameters":[]},{"name":"initRet6","returns":"char","parameters":[]},{"name":"initRet7","returns":"bool","parameters":[]},{"name":"initRet8","returns":"@list(bool)","parameters":[]},{"name":"initRet9","returns":"byte","parameters":[]},{"name":"initRet10","returns":"@list(byte)","parameters":[]},{"name":"initRet11","returns":"short","parameters":[]},{"name":"initRet12","returns":"@list(short)","parameters":[]},{"name":"initRet13","returns":"long","parameters":[]},{"name":"initRet14","returns":"@list(long)","parameters":[]},{"name":"initRet15","returns":"char","parameters":[]},{"name":"initRet16","returns":"@list(char)","parameters":[]},{"name":"initRet17","returns":"@list(String)","parameters":[]},{"name":"initRet18","returns":"@list(String)","parameters":[]},{"name":"init","returns":"void","parameters":[{"name":"name","type":"String"},{"name":"age","type":"int"},{"name":"gender","type":"@enum(com.infiniteloop.fidl_example.bean.Gender)"},{"name":"conversation","type":"com.infiniteloop.fidl_example.bean.Conversation"}]}]}

<|start_filename|>fidl/example/android/app/src/main/java/com/infiniteloop/fidl_example/bean/AUser.java<|end_filename|>
package com.infiniteloop.fidl_example.bean;

public class AUser extends User<String> {
    public AUser() {
    }

    public AUser(String uid, String name, int age) {
        super(uid, name, age);
    }
}


<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example.bean/MessageDirection.dart<|end_filename|>
enum MessageDirection {
  Receive,
  Send,
}


<|start_filename|>fidl/example/fidl/com.infiniteloop.fidl_example.bean.AUser.json<|end_filename|>
{"type":"com.infiniteloop.fidl_example.bean.AUser","kind":"class","fields":[],"superType":"com.infiniteloop.fidl_example.bean.User(String)"}

<|start_filename|>fidl/example/fidl/com.infiniteloop.fidl_example.bean.MessageDirection.json<|end_filename|>
{"type":"com.infiniteloop.fidl_example.bean.MessageDirection(Receive,Send)","kind":"enum","fields":[{"name":"value","type":"int"}],"superType":""}

<|start_filename|>fidl/example/fidl/com.infiniteloop.fidl_example.bean.MessageStatus.json<|end_filename|>
{"type":"com.infiniteloop.fidl_example.bean.MessageStatus(Played,Readed,Unread,AllMentioned,Mentioned,Send_Failure,Sent,Sending)","kind":"enum","fields":[{"name":"value","type":"int"}],"superType":""}

<|start_filename|>fidl/lib/type_util.dart<|end_filename|>
T getEnumFromString<T>(Iterable<T> values, String value) {
  return values.firstWhere((type) => type.toString().split(".").last == value,
      orElse: () => null);
}

String enumToString<T>(T enumValue) {
  return enumValue.toString().split('.').last;
}


<|start_filename|>fidl/example/android/fidlprocessor/src/main/java/com/infinateloop/fidlprocessor/FidlStructure.java<|end_filename|>
package com.infinateloop.fidlprocessor;

import com.sun.tools.javac.code.Type;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class FidlStructure {
    public String className;
    public List<Method> methods = new ArrayList<>();

    public FidlStructure(String className, List<Method> methodList) {
        this.className = className;
        this.methods.addAll(methodList);
    }

    public static class Method {
        public String name;
        public Type returns;
        public List<Parameter> parameters = new ArrayList<>();

        public Method(String name, Type returns, List<Parameter> parameterList) {
            this.name = name;
            this.returns = returns;
            this.parameters.addAll(parameterList);
        }
    }

    public static class Parameter {
        public String name;
        public Type type;

        public Parameter(String name, Type type) {
            this.name = name;
            this.type = type;
        }
    }

    public static class Class {
        public Type type;
        public List<Parameter> fields;

        public Class(Type type) {
            this.type = type;
            fields = TypeUtils.getTypeFields(type);
        }
    }

    public Set<Type> getTypes() {
        Set<Type> list = new HashSet<>();
        for (Method method : methods) {
            list.add(method.returns);
            for (Parameter parameter : method.parameters) {
                list.add(parameter.type);
            }
        }
        return list;
    }
}


<|start_filename|>fidl/example/lib/shape_button.dart<|end_filename|>
import 'package:flutter/material.dart';

class ShapeButton extends StatelessWidget {
  final VoidCallback onPressed;
  final Widget child;

  ShapeButton({@required this.onPressed, @required this.child});

  @override
  Widget build(BuildContext context) {
    return FlatButton(
        color: Colors.amber,
        highlightColor: Colors.amber[700],
        colorBrightness: Brightness.dark,
        splashColor: Colors.grey,
        child: this.child,
        shape:
            RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),
        onPressed: this.onPressed);
  }
}


<|start_filename|>fidl/android/src/main/java/com/infiniteloop/fidl/FidlPlugin.java<|end_filename|>
package com.infiniteloop.fidl;

import android.support.annotation.NonNull;

import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;

/**
 * FidlPlugin
 */
public class FidlPlugin implements FlutterPlugin, MethodCallHandler {
    private BinaryMessenger messenger;

    @Override
    public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
        final MethodChannel channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "fidl");
        channel.setMethodCallHandler(this);
        messenger = flutterPluginBinding.getBinaryMessenger();
    }

    public static void registerWith(Registrar registrar) {
        final MethodChannel channel = new MethodChannel(registrar.messenger(), "fidl");
        FidlPlugin plugin = new FidlPlugin();
        plugin.messenger = registrar.messenger();
        channel.setMethodCallHandler(plugin);
    }

    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
        if (call.method.equals("getPlatformVersion")) {
            result.success("Android " + android.os.Build.VERSION.RELEASE);
        } else if (call.method.equals("bind")) {
            String name = call.argument("name");
            int code = call.argument("code");
            boolean success = FidlChannel.bindChannel(messenger, name, code);
            result.success(success);
        } else if (call.method.equals("unbind")) {
            String name = call.argument("name");
            int code = call.argument("code");
            FidlChannel.unbindChannel(name, code);
            result.success(null);
        } else {
            result.notImplemented();
        }
    }

    @Override
    public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    }
}


<|start_filename|>fidl/example/android/app/src/main/java/com/infiniteloop/fidl_example/bean/ImageMessageContent.java<|end_filename|>
package com.infiniteloop.fidl_example.bean;

import android.os.Parcel;

public class ImageMessageContent extends MessageContent {
    public String localPath;
    public String remoteUrl;
    private byte[] thumbnailBytes;

    public ImageMessageContent(String path) {
        this.localPath = path;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        super.writeToParcel(dest, flags);
        dest.writeString(this.localPath);
        dest.writeString(this.remoteUrl);
        dest.writeByteArray(this.thumbnailBytes);
    }

    protected ImageMessageContent(Parcel in) {
        super(in);
        this.localPath = in.readString();
        this.remoteUrl = in.readString();
        this.thumbnailBytes = in.createByteArray();
    }

    public static final Creator<ImageMessageContent> CREATOR = new Creator<ImageMessageContent>() {
        @Override
        public ImageMessageContent createFromParcel(Parcel source) {
            return new ImageMessageContent(source);
        }

        @Override
        public ImageMessageContent[] newArray(int size) {
            return new ImageMessageContent[size];
        }
    };
}


<|start_filename|>fidl/android/src/main/java/com/infiniteloop/fidl/LogUtils.java<|end_filename|>
package com.infiniteloop.fidl;

import android.util.Log;

public class LogUtils {
    public static boolean DEBUG = true;
    private static final String TAG = "FIDL";

    public static void d(Object... objects) {
        if (!DEBUG) {
            return;
        }
        StringBuilder sb = new StringBuilder();
        for (Object obj : objects) {
            sb.append(obj.toString()).append("\n");
        }
        Log.d(TAG, sb.toString());
    }

    public static void i(Object... objects) {
        StringBuilder sb = new StringBuilder();
        for (Object obj : objects) {
            sb.append(obj.toString()).append("\n");
        }
        Log.i(TAG, sb.toString());
    }

    public static void e(Object... objects) {
        StringBuilder sb = new StringBuilder();
        for (Object obj : objects) {
            sb.append(obj.toString()).append("\n");
        }
        Log.e(TAG, sb.toString());
    }
}


<|start_filename|>fidl/android/src/main/java/com/infiniteloop/fidl/TypeLiteral.java<|end_filename|>
package com.infiniteloop.fidl;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.security.InvalidParameterException;

public class TypeLiteral<T> {

    public Type getSuperclassTypeParameter() {
        Class<?> subclass = getClass();
        Type superclass = subclass.getGenericSuperclass();
        if (superclass instanceof Class) {
            throw new InvalidParameterException("Missing type parameter.");
        }
        ParameterizedType parameterized = (ParameterizedType) superclass;
        return parameterized.getActualTypeArguments()[0];
    }
}


<|start_filename|>fidl/example/fidl/com.infiniteloop.fidl_example.bean.UserInfo.json<|end_filename|>
{"type":"com.infiniteloop.fidl_example.bean.UserInfo","kind":"class","fields":[{"name":"age","type":"int"},{"name":"name","type":"String"},{"name":"uid","type":"String"}],"superType":"?"}

<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example.bean/UserInfo.g.dart<|end_filename|>
// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'UserInfo.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

UserInfo _$UserInfoFromJson(Map<String, dynamic> json) {
  return UserInfo()
    ..age = json['age'] as int
    ..name = json['name'] as String
    ..uid = json['uid'] as String;
}

Map<String, dynamic> _$UserInfoToJson(UserInfo instance) => <String, dynamic>{
      'age': instance.age,
      'name': instance.name,
      'uid': instance.uid,
    };


<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example.bean/UiMessage.g.dart<|end_filename|>
// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'UiMessage.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

UiMessage _$UiMessageFromJson(Map<String, dynamic> json) {
  return UiMessage()
    ..message = json['message'] == null
        ? null
        : Message.fromJson(json['message'] as Map<String, dynamic>)
    ..progress = json['progress'] as int
    ..isChecked = json['isChecked'] as bool
    ..isFocus = json['isFocus'] as bool
    ..isDownloading = json['isDownloading'] as bool
    ..isPlaying = json['isPlaying'] as bool;
}

Map<String, dynamic> _$UiMessageToJson(UiMessage instance) => <String, dynamic>{
      'message': instance.message,
      'progress': instance.progress,
      'isChecked': instance.isChecked,
      'isFocus': instance.isFocus,
      'isDownloading': instance.isDownloading,
      'isPlaying': instance.isPlaying,
    };


<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example.bean/EmptyEnum.dart<|end_filename|>
enum EmptyEnum {
  none
}


<|start_filename|>fidl/android/src/main/java/com/infiniteloop/fidl/IChannel.java<|end_filename|>
package com.infiniteloop.fidl;

public interface IChannel {
}


<|start_filename|>fidl/example/android/fidlprocessor/src/main/java/com/infinateloop/fidlprocessor/JsonFidlStructure.java<|end_filename|>
package com.infinateloop.fidlprocessor;

import com.sun.tools.javac.code.Scope;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.TypeTag;
import com.sun.tools.javac.util.Filter;

import java.util.ArrayList;
import java.util.List;

import javax.lang.model.element.ElementKind;
import javax.lang.model.type.TypeKind;

import static com.infinateloop.fidlprocessor.TypeUtils.isList;
import static com.infinateloop.fidlprocessor.TypeUtils.isMap;
import static com.infinateloop.fidlprocessor.TypeUtils.isSet;
import static com.infinateloop.fidlprocessor.TypeUtils.typeEquals;

public class JsonFidlStructure {
    public String cls;
    public String kind;
    public List<Method> methods = new ArrayList<>();

    public static JsonFidlStructure from(FidlStructure structure) {
        JsonFidlStructure fidlStructure = new JsonFidlStructure(structure.className);
        for (FidlStructure.Method method : structure.methods) {
            Method mMethod = new Method(method.name, typeToString(method.returns));
            for (FidlStructure.Parameter parameter : method.parameters) {
                String type;
                if (parameter.type.asElement().getKind() == ElementKind.ENUM) {
                    type = "@enum(" + parameter.type.toString() + ")";
                } else {
                    type = typeToString(parameter.type);
                }
                mMethod.parameters.add(new Parameter(parameter.name, type));
            }
            fidlStructure.methods.add(mMethod);
        }
        fidlStructure.kind = "fidl";
        return fidlStructure;
    }

    private JsonFidlStructure(String className) {
        this.cls = className;
    }

    private static class Method {
        public String name;
        public String returns;
        public List<Parameter> parameters = new ArrayList<>();

        public Method(String name, String returns) {
            this.name = name;
            this.returns = returns;
        }
    }

    public static class Parameter {
        public String name;
        public String type;

        public Parameter(String name, String type) {
            this.name = name;
            this.type = type;
        }
    }

    public static class Class {
        public String type;
        public String kind;
        public List<Parameter> fields = new ArrayList<>();
        public String superType;

        private Class(String type) {
            this.type = type;
        }

        public static Class from(FidlStructure.Class clazz) {
            Class mClazz = new Class(typeToString(clazz.type));
            mClazz.superType = getSuperTypeString(clazz.type);
            for (FidlStructure.Parameter parameter : clazz.fields) {
                if (parameter.type.asElement().getKind() == ElementKind.ENUM) {
                    mClazz.fields.add(new Parameter(parameter.name, parameter.type.asElement().getQualifiedName().toString()));
                } else {
                    mClazz.fields.add(new Parameter(parameter.name, typeToString(parameter.type)));
                }
            }
            mClazz.kind = getTypeKind(clazz.type);
            return mClazz;
        }
    }

    private static String getSuperTypeString(Type type) {
        if (type.asElement().getKind() == ElementKind.ENUM) {
            return "";
        }
        if (type.getTag() == TypeTag.CLASS) {
            Type mType = ((Type.ClassType) type).supertype_field;
            if (mType != null) {
                return typeToString(mType);
            }
        }
        return "";
    }

    private static String typeToString(Type type) {
        if (typeEquals(type, void.class, Void.class)) {
            return "void";
        }
        if (typeEquals(type, boolean.class, Boolean.class)) {
            return "bool";
        }
        if (typeEquals(type, byte.class, Byte.class)) {
            return "byte";
        }
        if (typeEquals(type, short.class, Short.class)) {
            return "short";
        }
        if (typeEquals(type, int.class, Integer.class)) {
            return "int";
        }
        if (typeEquals(type, long.class, Long.class)) {
            return "long";
        }
        if (typeEquals(type, char.class, Character.class)) {
            return "char";
        }
        if (typeEquals(type, float.class, Float.class)) {
            return "float";
        }
        if (typeEquals(type, double.class, Double.class)) {
            return "double";
        }
        if (typeEquals(type, String.class)) {
            return "String";
        }
        if (type.getKind() == TypeKind.ARRAY) {
            Type.ArrayType arrayType = (Type.ArrayType) type;
            return "@list(" + typeToString(arrayType.elemtype) + ")";
        }

        if (type.getKind() == TypeKind.TYPEVAR) {
            // "?" 符号修饰泛型
            // TODO 支持泛型限制
            return "@Generic(" + type.toString() + ")"; // 泛型
        }

        if (type.toString().equals("java.lang.Object")) {
            return "?";
        }

        if (type.asElement().getKind() == ElementKind.ENUM) {
            StringBuilder sb = new StringBuilder(type.toString());
            sb.append("(");
            Scope scope = type.tsym.members();
            if (scope != null) {
                int size = 0;
                for (Symbol symbol : scope.getElements(new Filter<Symbol>() {
                    @Override
                    public boolean accepts(Symbol symbol) {
                        return symbol.getKind() == ElementKind.ENUM_CONSTANT;
                    }
                })) {
                    sb.append(symbol.toString());
                    sb.append(",");
                    size++;
                }
                if (size > 0) {
                    sb.setLength(sb.length() - 1);
                }
            }
            sb.append(")");
            return sb.toString();
        }

        if (!(type instanceof Type.ClassType)) {
            return type.toString();
        }

        Type.ClassType classType = (Type.ClassType) type;
        if (isSet(classType)) {
            List<Type> fields = classType.typarams_field;
            StringBuilder sb = new StringBuilder("@set(");
            if (fields != null && fields.size() > 0) {
                for (Type subType : fields) {
                    sb.append(typeToString(subType));
                }
            } else {
                sb.append("?");
            }
            sb.append(")");
            return sb.toString();
        }

        if (isList(classType)) {
            List<Type> fields = classType.typarams_field;
            StringBuilder sb = new StringBuilder("@list(");
            if (fields != null && fields.size() > 0) {
                for (Type subType : fields) {
                    sb.append(typeToString(subType));
                }
            } else {
                sb.append("?");
            }
            sb.append(")");
            return sb.toString();
        }

        if (isMap(classType)) {
            List<Type> fieldTypes = classType.typarams_field;
            if (fieldTypes == null || fieldTypes.size() == 0) {
                return "@map()";
            } else {
                return "@map(" + typeToString(fieldTypes.get(0))
                        + "," + typeToString(fieldTypes.get(1)) + ")";
            }
        }

        List<Type> fieldTypes = classType.typarams_field;
        if (fieldTypes != null && fieldTypes.size() > 0) {
            StringBuilder sb = new StringBuilder(classType.tsym.toString() + "(");
            for (int i = 0; i < fieldTypes.size(); i++) {
                sb.append(typeToString(fieldTypes.get(i)));
                if (i != fieldTypes.size() - 1) {
                    sb.append(",");
                }
            }
            sb.append(")");
            return sb.toString();
        }
        return type.toString();
    }

    private static String getTypeKind(Type type) {
        switch (type.asElement().getKind()) {
            case ENUM:
                return "enum";
            case CLASS:
            case INTERFACE:
                return "class";
            default:
                return "unknown";
        }
    }
}



<|start_filename|>fidl/example/android/fidlprocessor/src/main/java/com/infinateloop/fidlprocessor/TypeUtils.java<|end_filename|>
package com.infinateloop.fidlprocessor;

import com.squareup.javapoet.TypeName;
import com.sun.tools.javac.code.Scope;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.TypeTag;
import com.sun.tools.javac.util.Filter;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.type.TypeMirror;

public class TypeUtils {
    public static boolean isBasicType(Type type) {
        if (type.isPrimitiveOrVoid()) {
            return true;
        }
        return typeEquals(type,
                void.class, Void.class,
                boolean.class, Boolean.class,
                byte.class, Byte.class,
                short.class, Short.class,
                int.class, Integer.class,
                long.class, Long.class,
                char.class, Character.class,
                float.class, Float.class,
                double.class, Double.class,
                String.class,
                List.class,
                Map.class);
    }

    public static String typeToClassType(Type type) {
        if (typeEquals(type, void.class, Void.class)) {
            return "Void";
        }
        if (typeEquals(type, boolean.class, Boolean.class)) {
            return "Boolean";
        }
        if (typeEquals(type, byte.class, Byte.class)) {
            return "Byte";
        }
        if (typeEquals(type, short.class, Short.class)) {
            return "Short";
        }
        if (typeEquals(type, int.class, Integer.class)) {
            return "Integer";
        }
        if (typeEquals(type,
                long.class, Long.class)) {
            return "Long";
        }
        if (typeEquals(type, char.class, Character.class)) {
            return "Character";
        }
        if (typeEquals(type, float.class, Float.class)) {
            return "Float";
        }
        if (typeEquals(type, double.class, Double.class)) {
            return "Double";
        }
        return type.toString();
    }

    public static boolean typeEquals(Type type, Class... clazz) {
        TypeName typeName = argToType(type);
        for (Class cls : clazz) {
            if (typeName.equals(argToType(cls))) {
                return true;
            }
        }
        return false;
    }

    private static void collectNonBasicType(Type type, Set<Type> result) {
        if (type == null) {
            return;
        }
        if (TypeUtils.isBasicType(type)) {
            return;
        }
        if (result.contains(type)) {
            return;
        }

        // 处理不同的TypeTag类型，有ARRAY,CLASS
        TypeTag tag = type.getTag();
        if (tag == TypeTag.ARRAY) {
            Type elemType = ((Type.ArrayType) type).elemtype;
            if (elemType != null) {
                collectNonBasicType(elemType, result);
            }
            return;
        }

        if (tag != TypeTag.CLASS) {
            return;
        }
        Type.ClassType clsType = (Type.ClassType) type;
        // 处理ENUM枚举类
        if (clsType.tsym.getKind() == ElementKind.ENUM) {
            result.add(clsType);
            return;
        }

        // 处理泛型参数
        List<Type> params = clsType.typarams_field;
        if (params != null && params.size() > 0) {
            Set<Type> typeSet = new HashSet<>(params);
            collectNonBasicTypes(typeSet, result);
        }

        // 处理List/Map/Set/Queue等集合类
        if (isSet(clsType)) {
            return;
        }
        if (isList(clsType)) {
            return;
        }
        if (isMap(clsType)) {
            return;
        }

        if (clsType.tsym.type.toString().equals("java.lang.Object")) {
            return;
        }

        result.add(clsType.tsym.type);

        // 处理父类
        Type superType = ((Type.ClassType) type.tsym.type).supertype_field;
        if (superType != null) {
            collectNonBasicType(superType, result);
        }

        // 处理类型内部的成员变量的参数类型
        Scope scope = clsType.tsym.members();
        if (scope == null) {
            return;
        }
        for (Symbol symbol : scope.getElements(new Filter<Symbol>() {
            @Override
            public boolean accepts(Symbol symbol) {
                return symbol instanceof Symbol.VarSymbol &&
                        (!symbol.getModifiers().contains(Modifier.STATIC)) &&
                        (symbol.getKind() != ElementKind.ENUM);
            }
        })) {
            collectNonBasicType(symbol.type, result);
        }
    }

    public static void collectNonBasicTypes(Set<Type> types, Set<Type> result) {
        if (types == null) {
            return;
        }
        for (Type mType : types) {
            collectNonBasicType(mType, result);
        }
    }

    /**
     * 获取Type内部的成员变量参数和变量类型
     */
    public static List<FidlStructure.Parameter> getTypeFields(Type type) {
        List<FidlStructure.Parameter> types = new ArrayList<>();
        Scope scope = type.tsym.members();
        if (scope == null) {
            return types;
        }
        for (Symbol symbol : scope.getElements(new Filter<Symbol>() {
            @Override
            public boolean accepts(Symbol symbol) {
                return symbol instanceof Symbol.VarSymbol && (!symbol.getModifiers().contains(Modifier.STATIC));
            }
        })) {
            // enum 元素处理
            types.add(new FidlStructure.Parameter(symbol.name.toString(), symbol.type));
        }
        return types;
    }

    public static TypeName argToType(Object o) {
        if (o instanceof TypeName) {
            return (TypeName) o;
        } else if (o instanceof TypeMirror) {
            return TypeName.get((TypeMirror) o);
        } else if (o instanceof Element) {
            return TypeName.get(((Element) o).asType());
        } else if (o instanceof java.lang.reflect.Type) {
            return TypeName.get((java.lang.reflect.Type) o);
        } else {
            throw new IllegalArgumentException("expected type but was " + o);
        }
    }

    public static boolean isTypeExtends(Type.ClassType type, String... typeName) {
        // 参考instanceof的实现方法，遍历super链直到Object
        for (String name : typeName) {
            if (type.toString().equals(name) ||
                    type.tsym.toString().equals(name)) {
                return true;
            }
        }
        if (type.toString().equals("java.lang.Object")) {
            return false;
        }
        if (type.tsym.type.getTag() != TypeTag.CLASS) {
            return false;
        }

        List<Type> superTypes = ((Type.ClassType) type.tsym.type).interfaces_field;
        if (superTypes != null) {
            for (Type mType : superTypes) {
                if (mType.getTag() == TypeTag.CLASS) {
                    if (isTypeExtends((Type.ClassType) mType, typeName)) {
                        return true;
                    }
                }
            }
        }

        Type superType = ((Type.ClassType) type.tsym.type).supertype_field;
        if (superType != null && superType.getTag() == TypeTag.CLASS) {
            return isTypeExtends((Type.ClassType) superType, typeName);
        }
        return false;
    }
    // TODO 修改isBasicType方法，加上list/map/queue/stack的判定

    public static boolean isList(Type.ClassType type) {
        return isTypeExtends(type, "java.util.List", "java.util.Collection");
    }

    public static boolean isSet(Type.ClassType type) {
        return isTypeExtends(type, "java.util.Set");
    }

    public static boolean isMap(Type.ClassType type) {
        return isTypeExtends(type, "java.util.Map");
    }
}


<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example/IConversationService.g.dart<|end_filename|>
// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'IConversationService.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

FParam0 _$FParam0FromJson(Map<String, dynamic> json) {
  return FParam0(
    json['p0'] == null
        ? null
        : Conversation.fromJson(json['p0'] as Map<String, dynamic>),
  );
}

Map<String, dynamic> _$FParam0ToJson(FParam0 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FRet1 _$FRet1FromJson(Map<String, dynamic> json) {
  return FRet1(
    json['ret'] as String,
  );
}

Map<String, dynamic> _$FRet1ToJson(FRet1 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FRet2 _$FRet2FromJson(Map<String, dynamic> json) {
  return FRet2(
    (json['ret'] as List)
        ?.map((e) =>
            e == null ? null : UiMessage.fromJson(e as Map<String, dynamic>))
        ?.toList(),
  );
}

Map<String, dynamic> _$FRet2ToJson(FRet2 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FParam3 _$FParam3FromJson(Map<String, dynamic> json) {
  return FParam3(
    json['p0'] as String,
  );
}

Map<String, dynamic> _$FParam3ToJson(FParam3 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FRet4 _$FRet4FromJson(Map<String, dynamic> json) {
  return FRet4(
    json['ret'] as int,
  );
}

Map<String, dynamic> _$FRet4ToJson(FRet4 instance) => <String, dynamic>{
      'ret': instance.ret,
    };


<|start_filename|>fidl/example/fidl/com.infiniteloop.fidl_example.IConversationService.fidl.json<|end_filename|>
{"cls":"com.infiniteloop.fidl_example.IConversationService","kind":"fidl","methods":[{"name":"setupConversation","returns":"void","parameters":[{"name":"conversation","type":"com.infiniteloop.fidl_example.bean.Conversation"}]},{"name":"getConversationDesc","returns":"String","parameters":[]},{"name":"getMessages","returns":"@list(com.infiniteloop.fidl_example.bean.UiMessage)","parameters":[]},{"name":"sendMessage","returns":"void","parameters":[{"name":"message","type":"String"}]},{"name":"getMessageCount","returns":"int","parameters":[]}]}

<|start_filename|>fidl_model/lib/fidl_model.dart<|end_filename|>
library fidl_model;

import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:args/args.dart';
import 'package:path/path.dart' as path;
import 'build_runner.dart' as br;

const tpl = "import 'package:json_annotation/json_annotation.dart';\n"
    "%t\n"
    "part '%s.g.dart';\n\n"
    "@JsonSerializable()\n"
    "class %s {\n"
    "  %s();\n\n"
    "  %s\n"
    "  factory %s.fromJson(Map<String, dynamic> json) => _\$%sFromJson(json);\n\n"
    "  Map<String, dynamic> toJson() => _\$%sToJson(this);\n"
    "}\n";

const enumTpl = "enum %s {\n"
    "%s"
    "}\n";

void main(List<String> args) {
  String src;
  String dist;
  String tag;
  var parser = new ArgParser();
  parser.addOption('src',
      defaultsTo: './fidl',
      callback: (v) => src = v,
      help: "Specify the json directory.");
  parser.addOption('dist',
      defaultsTo: 'lib/fidl',
      callback: (v) => dist = v,
      help: "Specify the dist directory.");
  parser.addOption('tag',
      defaultsTo: '\$', callback: (v) => tag = v, help: "Specify the tag ");
  parser.parse(args);
  if (walk(src, dist, tag)) {
    br.run(['build', '--delete-conflicting-outputs']);
  }
}

bool walk(String srcDir, String distDir, String tag) {
  if (srcDir.endsWith("/")) srcDir = srcDir.substring(0, srcDir.length - 1);
  if (distDir.endsWith("/")) distDir = distDir.substring(0, distDir.length - 1);
  var src = Directory(srcDir);
  var list = src.listSync(recursive: true);
  String indexFile = "";
  if (list.isEmpty) return false;
  if (!Directory(distDir).existsSync()) {
    Directory(distDir).createSync(recursive: true);
  }

  list.forEach((f) {
    if (FileSystemEntity.isFileSync(f.path)) {
      var paths = path.basename(f.path).split(".");
      String basename = path.basename(f.path);
      if (basename.length > 9 && basename.endsWith("fidl.json")) {
        print('fidl code object');
        generateFidlFile(f, srcDir, distDir);
        return;
      }
      if (paths.last.toLowerCase() != "json") return;
      generateModelFile(f, srcDir, distDir);
    }
  });
//  if (indexFile.isNotEmpty) {
//    File(path.join(distDir, "index.dart")).writeAsStringSync(indexFile);
//  }
//  return indexFile.isNotEmpty;
  return true;
}

void generateModelFile(File f, String srcDir, String distDir) {
  String basename = path.basename(f.path);
  basename = basename.substring(0, basename.lastIndexOf("."));
  int index = basename.lastIndexOf(".");
  String name;
  String dirPath;
  if (index < 0) {
    name = basename;
    dirPath = '.';
  } else {
    name = basename.substring(index + 1);
    dirPath = basename.substring(0, index);
  }
  if (name.startsWith("_")) return;

  //生成模板
  var map = json.decode(f.readAsStringSync());
  StringBuffer attrs = new StringBuffer();
  String kind = map['kind'];
  String type = map['type'];

  if (type == null || type.length < 1) {
    return;
  }

  String dist = '';
  // 保证类以大写字母为首
  String className = name[0].toUpperCase() + name.substring(1);

  if (kind == 'fidl') {
    generateFidlFile(f, srcDir, distDir);
    return;
  } else if (kind == 'enum') {
    int leftIndex = type.indexOf('(');
    if (leftIndex >= 0) {
      int rightIndex = type.lastIndexOf(')');
      String middle = type.substring(leftIndex + 1, rightIndex);
      // 生成枚举
      // 对于没有元素的枚举，自动添加一个`none`元素，否则会有dart语法错误
      if (middle.length < 1) {
        attrs.writeln("  none");
      } else {
        List<String> fields = middle.split(',');
        fields.forEach((field) {
          attrs.write("  ");
          attrs.write(field);
          attrs.writeln(',');
        });
      }
    }

    dist = format(enumTpl, [className, attrs.toString()]);
  } else if (kind == 'class') {
    print('class type.');

    String superType = map['superType'];
    List<dynamic> list = map['fields'];
    Map<String, String> imports = Map<String, String>();

    String classDesc = parseType(type, imports);
    if (superType != null && superType.length > 0) {
      classDesc += ' extends ' + parseType(superType, imports);
    }

    // 遍历内部变量
    list.forEach((field) {
      String fieldType = field['type'];
      if (fieldType.contains('@Generic')) {
        // @GenericConverter()用于给泛型类生成fromJson/toJson方法，避免编译错误
        attrs.writeln('@GenericConverter()');
        attrs.write("  ");
        imports['package:fidl/fidl'] = '';
      }
      attrs.write(parseType(field['type'], imports));
      attrs.write(' ');
      attrs.write(field['name']);
      attrs.writeln(';');
      attrs.write("  ");
    });

    dist = format(tpl, [
      name,
      classDesc,
      className,
      attrs.toString(),
      className,
      className,
      className
    ]);

    String _import = '';
    imports.remove(basename);
    imports.forEach((String type, String alias) {
      int index = type.lastIndexOf('.');
      String package = '';
      String shortName = type;
      if (index >= 0) {
        package = type.substring(0, index);
        shortName = type.substring(index + 1);

        if (package == dirPath) {
          _import += 'import "$shortName.dart"';
        } else {
          _import += 'import "../$package/$shortName.dart"';
        }
      } else {
        _import += 'import "$shortName.dart"';
      }

      if (alias != null && alias.length > 0) {
        _import += ' as $alias';
      }
      _import += ';\n';
    });
    dist = dist.replaceFirst("%t", _import);
  } else {
    return;
  }

  //将生成的模板输出
  var p =
  f.parent.path.replaceFirst(srcDir, distDir + path.separator + dirPath);
  p += path.separator + name + '.dart';
  File(p)
    ..createSync(recursive: true)
    ..writeAsStringSync(dist);
}

String changeFirstChar(String str, [bool upper = true]) {
  return (upper ? str[0].toUpperCase() : str[0].toLowerCase()) +
      str.substring(1);
}

bool isBuiltInType(String type) {
  return ['int', 'num', 'string', 'double', 'map', 'list'].contains(type);
}

const fidlTpl = '''import 'dart:async';
import 'package:flutter/services.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:fidl/fidl.dart';
%t
part '%s.g.dart';

class %s {
  static const String CHANNEL_NAME = '%s';
  static const MethodChannel _channel =
      const MethodChannel(CHANNEL_NAME, const MultiMethodCodec());

%s
}

%s
''';

/// 生成FIDL Channel类
void generateFidlFile(File f, String srcDir, String distDir) {
  var map = json.decode(f.readAsStringSync());
  String cls = map['cls'];
  int index = cls.lastIndexOf('.');
  String package = '.';
  String clsName;
  if (index < 0) {
    clsName = cls;
  } else {
    package = cls.substring(0, index);
    clsName = cls.substring(index + 1);
  }

  Map<String, String> imports = Map<String, String>();
  List methods = map['methods'];
  StringBuffer attrs = StringBuffer();
  StringBuffer extras = StringBuffer();
  generateFidlMethods(methods, attrs, imports, extras);

  String dist = format(
      fidlTpl, [clsName, clsName, cls, attrs.toString(), extras.toString()]);

  String _import = '';
  imports.remove(cls);
  imports.forEach((String type, String alias) {
    int index = type.lastIndexOf('.');
    String packageStr = '';
    String shortName = type;
    if (index >= 0) {
      packageStr = type.substring(0, index);
      shortName = type.substring(index + 1);

      if (packageStr == package) {
        _import += 'import "$shortName.dart"';
      } else {
        _import += 'import "../$packageStr/$shortName.dart"';
      }
    } else {
      _import += 'import "$shortName.dart"';
    }

    if (alias != null && alias.length > 0) {
      _import += ' as $alias';
    }
    _import += ';\n';
  });
  dist = dist.replaceFirst("%t", _import);

  var p =
  f.parent.path.replaceFirst(srcDir, '$distDir${path.separator}$package');
  p += '${path.separator}$clsName.dart';
  File(p)
    ..createSync(recursive: true)
    ..writeAsStringSync(dist);
  var relative = p.replaceFirst(distDir + path.separator, "");
//  indexFile += "export '$relative' ; \n";
}

const innerClassTpl = "@JsonSerializable()\n"
    "class %s {\n"
    "  %s(%s);\n\n"
    "%s\n"
    "  factory %s.fromJson(Map<String, dynamic> json) => _\$%sFromJson(json);\n\n"
    "  Map<String, dynamic> toJson() => _\$%sToJson(this);\n"
    "}\n";

/// 生成FIDL类的方法，以及参数Model类和返回值Model类
void generateFidlMethods(List methods, StringBuffer attrs,
    Map<String, String> imports, StringBuffer extras) {
  int methodIndex = -1;
  methods?.forEach((method) {
    methodIndex++;

    String methodName = method['name'];
    String returns = method['returns'];
    String retType = parseType(returns, imports);
    List parameters = method['parameters'];

    // 生成内部类
    String returnClassName = 'FRet$methodIndex';

    String methodClassName = 'FParam$methodIndex';
    StringBuffer classAttr = StringBuffer();
    String methodClassConstructorAttr = '';
    String methodParams = '';

    if (!isVoidType(retType)) {
      String retClass = format(innerClassTpl, [
        returnClassName,
        returnClassName,
        'this.ret',
        '  $retType ret;\n',
        returnClassName,
        returnClassName,
        returnClassName
      ]);
      extras.write(retClass);
    }

    attrs.write('  static Future<$retType> $methodName');
    attrs.write('(');

    if (parameters != null && parameters.length > 0) {
      int i = 0;
      parameters.forEach((param) {
        String paramType = param['type'];
        String paramName = param['name'];
        String realType = parseType(paramType, imports);
        attrs.write('$realType $paramName');

        // 局部变量和构造参数
        classAttr.write('  $realType p$i;\n');
        methodClassConstructorAttr += 'this.p$i';
        methodParams += '$paramName';

        if (i != parameters.length - 1) {
          attrs.write(', ');
          methodClassConstructorAttr += ', ';
          methodParams += ', ';
        }
        i++;
      });

      String paramClass = format(innerClassTpl, [
        methodClassName,
        methodClassName,
        methodClassConstructorAttr,
        classAttr,
        methodClassName,
        methodClassName,
        methodClassName
      ]);
      extras.write(paramClass);
    }

    attrs.write(') ');
    attrs.write('async {\n');

    if (parameters != null && parameters.length > 0) {
      int i = 0;
      String encodeParams = '';
      parameters.forEach((param) {
        attrs.write(
            '    var p$i = $methodClassName($methodParams).toJson()[\'p$i\'];\n');
        encodeParams += 'p$i';
        if (i != parameters.length - 1) {
          encodeParams += ', ';
        }
        i++;
      });
      attrs
          .write('    var param = Fidl.objectCodec.encode([$encodeParams]);\n');
      attrs.write(
          '    var ret = await _channel.invokeMethod(\'$methodName\', param);\n');
    } else {
      attrs.write(
          '    var ret = await _channel.invokeMethod(\'$methodName\');\n');
    }

    if (!isVoidType(retType)) {
      attrs.write('    var json = Fidl.objectCodec.decode(ret[0]);\n');
      attrs.write('    return $returnClassName.fromJson(json).ret;\n');
    }

    attrs.write('  }\n');
  });
}

bool isBasicType(String type) {
  switch (type) {
    case 'int':
    case 'short':
    case 'byte':
    case 'long':
    case 'char':
    case 'float':
    case 'double':
    case 'String':
      return true;
  }
  return false;
}

bool isVoidType(String type) {
  return type == 'void';
}

bool isEnumType(String type) {
  return type.startsWith('@enum');
}

/// import第一个字段表示类型，第二个字段表示导入别名
/// 推算类型
String parseType(String typeName, Map<String, String> imports) {
  if (typeName == null || typeName.length < 1) {
    return "";
  }

  if (imports.containsKey(typeName)) {
    String alias = imports[typeName];
    int index = typeName.lastIndexOf('.');
    String name;
    if (index < 0) {
      name = typeName;
    } else {
      name = typeName.substring(index + 1);
    }
    if (alias != null && alias.length > 0) {
      name = alias + '.' + name;
    }
    return name;
  }

  int leftIndex = typeName.indexOf('(');
  if (leftIndex < 0) {
    switch (typeName) {
      case 'int':
      case 'short':
      case 'byte':
      case 'long': // TODO java不支持int64，java解析时应当做Long解析
      case 'char':
        return 'int';
      case 'float':
      case 'double':
        return 'double';
      case 'void':
        return 'void';
      case 'var':
        return 'dynamic';
      case 'String':
        return 'String';
      case '?':
        return 'Object';
      case 'bool':
        return 'bool';
      case '@list':
        return 'List';
      case '@set':
        return 'Set';
      case '@map':
        return 'Map';
      default:
        {
          addUniqueTypeToMap(typeName, imports);
          return parseType(typeName, imports);
        }
    }
  }

  String left = typeName.substring(0, leftIndex);
  int rightIndex = typeName.lastIndexOf(')');
  String middle = typeName.substring(leftIndex + 1, rightIndex);
  switch (left) {
    case '@list':
      {
        if (middle == null || middle.length < 1) {
          return 'List';
        }
        return 'List<' + parseType(middle, imports) + '>';
      }
    case '@set':
      {
        if (middle == null || middle.length < 1) {
          return 'Set';
        }
        return 'Set<' + parseType(middle, imports) + '>';
      }
    case '@map':
      {
        List<String> params = splitParams(middle);
        if (params.length < 2) {
          return 'Map';
        }
        return 'Map<' +
            parseType(params[0], imports) +
            ',' +
            parseType(params[1], imports) +
            '>';
      }
    case '@Generic':
      {
        return middle;
      }
    case '@enum':
      {
        addUniqueTypeToMap(middle, imports);
        return parseType(middle, imports);
      }
  }

  List<String> params = splitParams(middle);
  if (params.length < 1) {
    return parseType(typeName, imports);
  }
  String type = parseType(left, imports) + '<';
  for (int i = 0; i < params.length; i++) {
    type += parseType(params[i], imports);
    if (i != params.length - 1) {
      type += ',';
    }
  }
  type += '>';
  return type;
}

/// 解析参数
/// 如：字符串"(String,@list(String),int)"，解析后得到[String,@list(String),int]
List<String> splitParams(String typeStr) {
  List<String> params = [];
  if (typeStr == null || typeStr.length < 1) {
    return params;
  }
  int len = typeStr.length;

  int bracketsWeight = 0;
  int startIndex = 0;
  for (int i = 0; i < len; i++) {
    if (typeStr[i] == '(') {
      bracketsWeight++;
    } else if (typeStr[i] == ')') {
      bracketsWeight--;
    } else if (typeStr[i] == ',' && bracketsWeight == 0) {
      params.add(typeStr.substring(startIndex, i));
      startIndex = i + 1;
    }
    if (i == len - 1) {
      params.add(typeStr.substring(startIndex, len));
    }
  }
  return params;
}

/// 返回alias 别名
String addUniqueTypeToMap(String typeName, Map<String, String> imports) {
  if (imports.containsKey(typeName)) {
    return imports[typeName];
  }

  int index = typeName.lastIndexOf('.');
  String name;
  if (index < 0) {
    name = typeName;
  } else {
    name = typeName.substring(index + 1);
  }

  String mAlias = '';
  imports.forEach((String type, String alias) {
    if (type.endsWith('.$name') || type == name) {
      do {
        mAlias = 't${Random().nextInt(9999)}';
      } while (imports.containsValue(mAlias));
      return;
    }
  });
  imports[typeName] = mAlias;
  return mAlias;
}

/// 替换模板占位符
String format(String fmt, List<Object> params) {
  int matchIndex = 0;
  String replace(Match m) {
    if (matchIndex < params.length) {
      switch (m[0]) {
        case "%s":
          return params[matchIndex++].toString();
      }
    } else {
      throw new Exception("Missing parameter for string format");
    }
    throw new Exception("Invalid format string: " + m[0].toString());
  }

  return fmt.replaceAllMapped("%s", replace);
}


<|start_filename|>fidl/example/android/app/src/main/java/com/infiniteloop/fidl_example/FastJsonObjectCodec.java<|end_filename|>
package com.infiniteloop.fidl_example;

import com.alibaba.fastjson.JSON;
import com.infiniteloop.fidl.LogUtils;
import com.infiniteloop.fidl.ObjectCodec;
import com.infiniteloop.fidl.TypeLiteral;

import java.util.ArrayList;
import java.util.List;

public class FastJsonObjectCodec implements ObjectCodec {
    private static final byte[] NULL = "\"null\"".getBytes();

    @Override
    public List<byte[]> encode(Object... objects) {
        List<byte[]> bytes = new ArrayList<>();
        if (objects == null || objects.length == 0) {
            bytes.add(NULL);
        } else {
            for (Object obj : objects) {
                if (obj == null) {
                    bytes.add(NULL);
                } else {
                    bytes.add(JSON.toJSONString(obj).getBytes());
                }
            }
        }
        return bytes;
    }

    @Override
    public <T> T decode(byte[] input, TypeLiteral<T> type) {
        T ret = JSON.parseObject(input, type.getSuperclassTypeParameter());
        LogUtils.d(ret);
        return ret;
    }
}


<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example/IChatService.g.dart<|end_filename|>
// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'IChatService.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

FRet0 _$FRet0FromJson(Map<String, dynamic> json) {
  return FRet0(
    json['ret'] as bool,
  );
}

Map<String, dynamic> _$FRet0ToJson(FRet0 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FParam0 _$FParam0FromJson(Map<String, dynamic> json) {
  return FParam0(
    json['p0'] == null
        ? null
        : User.fromJson(json['p0'] as Map<String, dynamic>),
  );
}

Map<String, dynamic> _$FParam0ToJson(FParam0 instance) => <String, dynamic>{
      'p0': instance.p0,
    };


<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example.bean/Message.dart<|end_filename|>
import 'package:json_annotation/json_annotation.dart';
import "MessageStatus.dart";
import "MessageDirection.dart";
import "MessageContent.dart";
import "Conversation.dart";

part 'Message.g.dart';

@JsonSerializable()
class Message extends Object {
  Message();

  int serverTime;
  int messageUid;
  MessageStatus status;
  MessageDirection direction;
  MessageContent content;
  List<String> toUsers;
  String sender;
  Conversation conversation;
  int messageId;
  
  factory Message.fromJson(Map<String, dynamic> json) => _$MessageFromJson(json);

  Map<String, dynamic> toJson() => _$MessageToJson(this);
}


<|start_filename|>fidl/example/fidl/com.infiniteloop.fidl_example.bean.MessageContent.json<|end_filename|>
{"type":"com.infiniteloop.fidl_example.bean.MessageContent","kind":"class","fields":[{"name":"pushContent","type":"String"},{"name":"extra","type":"String"},{"name":"mentionedTargets","type":"@list(String)"},{"name":"mentionedType","type":"int"}],"superType":"?"}

<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example.bean/User.g.dart<|end_filename|>
// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'User.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

User<T> _$UserFromJson<T>(Map<String, dynamic> json) {
  return User<T>()
    ..country = GenericConverter<T>().fromJson(json['country'])
    ..age = json['age'] as int
    ..name = json['name'] as String
    ..uid = json['uid'] as String;
}

Map<String, dynamic> _$UserToJson<T>(User<T> instance) => <String, dynamic>{
      'country': GenericConverter<T>().toJson(instance.country),
      'age': instance.age,
      'name': instance.name,
      'uid': instance.uid,
    };


<|start_filename|>fidl/example/android/app/src/main/java/com/infiniteloop/fidl_example/IUserService.java<|end_filename|>
package com.infiniteloop.fidl_example;

import com.infinateloop.fidl.annotation.FIDL;
import com.infiniteloop.fidl_example.bean.AUser;
import com.infiniteloop.fidl_example.bean.Conversation;
import com.infiniteloop.fidl_example.bean.EmptyEnum;
import com.infiniteloop.fidl_example.bean.Gender;
import com.infiniteloop.fidl_example.bean.MessageStatus;
import com.infiniteloop.fidl_example.bean.User;
import com.infiniteloop.fidl_example.bean.UserInfo;

import java.util.AbstractCollection;
import java.util.AbstractList;
import java.util.AbstractMap;
import java.util.AbstractQueue;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Queue;
import java.util.Set;
import java.util.Stack;
import java.util.TreeSet;
import java.util.Vector;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;

@FIDL
public interface IUserService {
    // 基础类型
    void initArr0(int[] ids);
    void initArr1(int[][] ids);

    // 枚举
    void initEnum0(EmptyEnum e);
    String initEnum1(MessageStatus status);

    // 集合
    void initList0(List<String> ids);
    void initList1(Collection<String> ids);
    void initList2(Vector<String> ids);
    void initList3(AbstractList<String> ids);
    void initList4(AbstractCollection<String> ids);
    void initList5(CopyOnWriteArrayList<String> ids);
    void initList6(LinkedList<String> ids);
    void initList7(Stack<String> ids);

    // TODO Queue细分
    void initList8(Queue ids);
    void initList9(AbstractQueue<String> ids);
    void initList10(BlockingQueue ids);


    void initSet0(Set ids);
    void initSet1(AbstractSet ids);
    void initSet2(HashSet<String> ids);
    void initSet3(CopyOnWriteArraySet ids);
    void initSet4(TreeSet<String> ids);
    void initSet5(LinkedHashSet<String> ids);

    void initMap0(Map<String,String> ids);
    void initMap1(AbstractMap map);
    void initMap2(AbstractMap<?, String> map);
    void initMap3(AbstractMap<?, Object> map);
    void initMap4(AbstractMap<?, ?> map);
    void initMap5(HashMap<?,List<HashMap<String,String>>> map);
    void initMap6(HashMap<String,String> ids);
    void initMap7(Hashtable<String,String> ids);
    void initMap8(Properties ids);

    void initObj0(UserInfo info);
    void initObj1(User user);
    void initObj2(AUser user);
    void initObj3(User<String> user);

    String initRet0();
    boolean initRet1();
    int initRet2();
    byte initRet3();
    short initRet4();
    long initRet5();
    char initRet6();

    Boolean initRet7();
    boolean[] initRet8();
    Byte initRet9();
    byte[] initRet10();
    Short initRet11();
    short[] initRet12();
    Long initRet13();
    long[] initRet14();
    Character initRet15();
    char[] initRet16();

    String[] initRet17();
    List<String> initRet18();

    void init(String name, Integer age, Gender gender, Conversation conversation);
}


<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example/IConversationService.dart<|end_filename|>
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:fidl/fidl.dart';
import "../com.infiniteloop.fidl_example.bean/Conversation.dart";
import "../com.infiniteloop.fidl_example.bean/UiMessage.dart";

part 'IConversationService.g.dart';

class IConversationService {
  static const String CHANNEL_NAME = 'com.infiniteloop.fidl_example.IConversationService';
  static const MethodChannel _channel =
      const MethodChannel(CHANNEL_NAME, const MultiMethodCodec());

  static Future<void> setupConversation(Conversation conversation) async {
    var p0 = FParam0(conversation).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('setupConversation', param);
  }
  static Future<String> getConversationDesc() async {
    var ret = await _channel.invokeMethod('getConversationDesc');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet1.fromJson(json).ret;
  }
  static Future<List<UiMessage>> getMessages() async {
    var ret = await _channel.invokeMethod('getMessages');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet2.fromJson(json).ret;
  }
  static Future<void> sendMessage(String message) async {
    var p0 = FParam3(message).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('sendMessage', param);
  }
  static Future<int> getMessageCount() async {
    var ret = await _channel.invokeMethod('getMessageCount');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet4.fromJson(json).ret;
  }

}

@JsonSerializable()
class FParam0 {
  FParam0(this.p0);

  Conversation p0;

  factory FParam0.fromJson(Map<String, dynamic> json) => _$FParam0FromJson(json);

  Map<String, dynamic> toJson() => _$FParam0ToJson(this);
}
@JsonSerializable()
class FRet1 {
  FRet1(this.ret);

  String ret;

  factory FRet1.fromJson(Map<String, dynamic> json) => _$FRet1FromJson(json);

  Map<String, dynamic> toJson() => _$FRet1ToJson(this);
}
@JsonSerializable()
class FRet2 {
  FRet2(this.ret);

  List<UiMessage> ret;

  factory FRet2.fromJson(Map<String, dynamic> json) => _$FRet2FromJson(json);

  Map<String, dynamic> toJson() => _$FRet2ToJson(this);
}
@JsonSerializable()
class FParam3 {
  FParam3(this.p0);

  String p0;

  factory FParam3.fromJson(Map<String, dynamic> json) => _$FParam3FromJson(json);

  Map<String, dynamic> toJson() => _$FParam3ToJson(this);
}
@JsonSerializable()
class FRet4 {
  FRet4(this.ret);

  int ret;

  factory FRet4.fromJson(Map<String, dynamic> json) => _$FRet4FromJson(json);

  Map<String, dynamic> toJson() => _$FRet4ToJson(this);
}



<|start_filename|>fidl/example/android/app/src/main/java/com/infiniteloop/fidl_example/bean/TextMessageContent.java<|end_filename|>
package com.infiniteloop.fidl_example.bean;

import android.os.Parcel;

public class TextMessageContent extends MessageContent {
    private String content;

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        super.writeToParcel(dest, flags);
        dest.writeString(this.content);
    }

    public TextMessageContent() {
    }

    public TextMessageContent(String content) {
        this.content = content;
        this.extra = content;
    }

    protected TextMessageContent(Parcel in) {
        super(in);
        this.content = in.readString();
    }

    public static final Creator<TextMessageContent> CREATOR = new Creator<TextMessageContent>() {
        @Override
        public TextMessageContent createFromParcel(Parcel source) {
            return new TextMessageContent(source);
        }

        @Override
        public TextMessageContent[] newArray(int size) {
            return new TextMessageContent[size];
        }
    };
}


<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example/IUserService.dart<|end_filename|>
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:fidl/fidl.dart';
import "../com.infiniteloop.fidl_example.bean/EmptyEnum.dart";
import "../com.infiniteloop.fidl_example.bean/MessageStatus.dart";
import "../com.infiniteloop.fidl_example.bean/UserInfo.dart";
import "../com.infiniteloop.fidl_example.bean/User.dart";
import "../com.infiniteloop.fidl_example.bean/AUser.dart";
import "../com.infiniteloop.fidl_example.bean/Gender.dart";
import "../com.infiniteloop.fidl_example.bean/Conversation.dart";

part 'IUserService.g.dart';

class IUserService {
  static const String CHANNEL_NAME = 'com.infiniteloop.fidl_example.IUserService';
  static const MethodChannel _channel =
      const MethodChannel(CHANNEL_NAME, const MultiMethodCodec());

  static Future<void> initArr0(List<int> ids) async {
    var p0 = FParam0(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initArr0', param);
  }
  static Future<void> initArr1(List<List<int>> ids) async {
    var p0 = FParam1(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initArr1', param);
  }
  static Future<void> initEnum0(EmptyEnum e) async {
    var p0 = FParam2(e).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initEnum0', param);
  }
  static Future<String> initEnum1(MessageStatus status) async {
    var p0 = FParam3(status).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initEnum1', param);
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet3.fromJson(json).ret;
  }
  static Future<void> initList0(List<String> ids) async {
    var p0 = FParam4(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initList0', param);
  }
  static Future<void> initList1(List<String> ids) async {
    var p0 = FParam5(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initList1', param);
  }
  static Future<void> initList2(List<String> ids) async {
    var p0 = FParam6(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initList2', param);
  }
  static Future<void> initList3(List<String> ids) async {
    var p0 = FParam7(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initList3', param);
  }
  static Future<void> initList4(List<String> ids) async {
    var p0 = FParam8(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initList4', param);
  }
  static Future<void> initList5(List<String> ids) async {
    var p0 = FParam9(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initList5', param);
  }
  static Future<void> initList6(List<String> ids) async {
    var p0 = FParam10(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initList6', param);
  }
  static Future<void> initList7(List<String> ids) async {
    var p0 = FParam11(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initList7', param);
  }
  static Future<void> initList8(List<Object> ids) async {
    var p0 = FParam12(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initList8', param);
  }
  static Future<void> initList9(List<String> ids) async {
    var p0 = FParam13(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initList9', param);
  }
  static Future<void> initList10(List<Object> ids) async {
    var p0 = FParam14(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initList10', param);
  }
  static Future<void> initSet0(Set<Object> ids) async {
    var p0 = FParam15(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initSet0', param);
  }
  static Future<void> initSet1(Set<Object> ids) async {
    var p0 = FParam16(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initSet1', param);
  }
  static Future<void> initSet2(Set<String> ids) async {
    var p0 = FParam17(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initSet2', param);
  }
  static Future<void> initSet3(Set<Object> ids) async {
    var p0 = FParam18(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initSet3', param);
  }
  static Future<void> initSet4(Set<String> ids) async {
    var p0 = FParam19(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initSet4', param);
  }
  static Future<void> initSet5(Set<String> ids) async {
    var p0 = FParam20(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initSet5', param);
  }
  static Future<void> initMap0(Map<String,String> ids) async {
    var p0 = FParam21(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initMap0', param);
  }
  static Future<void> initMap1(Map map) async {
    var p0 = FParam22(map).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initMap1', param);
  }
  static Future<void> initMap2(Map<Object,String> map) async {
    var p0 = FParam23(map).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initMap2', param);
  }
  static Future<void> initMap3(Map<Object,Object> map) async {
    var p0 = FParam24(map).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initMap3', param);
  }
  static Future<void> initMap4(Map<Object,Object> map) async {
    var p0 = FParam25(map).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initMap4', param);
  }
  static Future<void> initMap5(Map<Object,List<Map<String,String>>> map) async {
    var p0 = FParam26(map).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initMap5', param);
  }
  static Future<void> initMap6(Map<String,String> ids) async {
    var p0 = FParam27(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initMap6', param);
  }
  static Future<void> initMap7(Map<String,String> ids) async {
    var p0 = FParam28(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initMap7', param);
  }
  static Future<void> initMap8(Map ids) async {
    var p0 = FParam29(ids).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initMap8', param);
  }
  static Future<void> initObj0(UserInfo info) async {
    var p0 = FParam30(info).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initObj0', param);
  }
  static Future<void> initObj1(User user) async {
    var p0 = FParam31(user).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initObj1', param);
  }
  static Future<void> initObj2(AUser user) async {
    var p0 = FParam32(user).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initObj2', param);
  }
  static Future<void> initObj3(User<String> user) async {
    var p0 = FParam33(user).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('initObj3', param);
  }
  static Future<String> initRet0() async {
    var ret = await _channel.invokeMethod('initRet0');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet34.fromJson(json).ret;
  }
  static Future<bool> initRet1() async {
    var ret = await _channel.invokeMethod('initRet1');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet35.fromJson(json).ret;
  }
  static Future<int> initRet2() async {
    var ret = await _channel.invokeMethod('initRet2');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet36.fromJson(json).ret;
  }
  static Future<int> initRet3() async {
    var ret = await _channel.invokeMethod('initRet3');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet37.fromJson(json).ret;
  }
  static Future<int> initRet4() async {
    var ret = await _channel.invokeMethod('initRet4');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet38.fromJson(json).ret;
  }
  static Future<int> initRet5() async {
    var ret = await _channel.invokeMethod('initRet5');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet39.fromJson(json).ret;
  }
  static Future<int> initRet6() async {
    var ret = await _channel.invokeMethod('initRet6');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet40.fromJson(json).ret;
  }
  static Future<bool> initRet7() async {
    var ret = await _channel.invokeMethod('initRet7');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet41.fromJson(json).ret;
  }
  static Future<List<bool>> initRet8() async {
    var ret = await _channel.invokeMethod('initRet8');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet42.fromJson(json).ret;
  }
  static Future<int> initRet9() async {
    var ret = await _channel.invokeMethod('initRet9');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet43.fromJson(json).ret;
  }
  static Future<List<int>> initRet10() async {
    var ret = await _channel.invokeMethod('initRet10');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet44.fromJson(json).ret;
  }
  static Future<int> initRet11() async {
    var ret = await _channel.invokeMethod('initRet11');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet45.fromJson(json).ret;
  }
  static Future<List<int>> initRet12() async {
    var ret = await _channel.invokeMethod('initRet12');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet46.fromJson(json).ret;
  }
  static Future<int> initRet13() async {
    var ret = await _channel.invokeMethod('initRet13');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet47.fromJson(json).ret;
  }
  static Future<List<int>> initRet14() async {
    var ret = await _channel.invokeMethod('initRet14');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet48.fromJson(json).ret;
  }
  static Future<int> initRet15() async {
    var ret = await _channel.invokeMethod('initRet15');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet49.fromJson(json).ret;
  }
  static Future<List<int>> initRet16() async {
    var ret = await _channel.invokeMethod('initRet16');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet50.fromJson(json).ret;
  }
  static Future<List<String>> initRet17() async {
    var ret = await _channel.invokeMethod('initRet17');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet51.fromJson(json).ret;
  }
  static Future<List<String>> initRet18() async {
    var ret = await _channel.invokeMethod('initRet18');
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet52.fromJson(json).ret;
  }
  static Future<void> init(String name, int age, Gender gender, Conversation conversation) async {
    var p0 = FParam53(name, age, gender, conversation).toJson()['p0'];
    var p1 = FParam53(name, age, gender, conversation).toJson()['p1'];
    var p2 = FParam53(name, age, gender, conversation).toJson()['p2'];
    var p3 = FParam53(name, age, gender, conversation).toJson()['p3'];
    var param = Fidl.objectCodec.encode([p0, p1, p2, p3]);
    var ret = await _channel.invokeMethod('init', param);
  }

}

@JsonSerializable()
class FParam0 {
  FParam0(this.p0);

  List<int> p0;

  factory FParam0.fromJson(Map<String, dynamic> json) => _$FParam0FromJson(json);

  Map<String, dynamic> toJson() => _$FParam0ToJson(this);
}
@JsonSerializable()
class FParam1 {
  FParam1(this.p0);

  List<List<int>> p0;

  factory FParam1.fromJson(Map<String, dynamic> json) => _$FParam1FromJson(json);

  Map<String, dynamic> toJson() => _$FParam1ToJson(this);
}
@JsonSerializable()
class FParam2 {
  FParam2(this.p0);

  EmptyEnum p0;

  factory FParam2.fromJson(Map<String, dynamic> json) => _$FParam2FromJson(json);

  Map<String, dynamic> toJson() => _$FParam2ToJson(this);
}
@JsonSerializable()
class FRet3 {
  FRet3(this.ret);

  String ret;

  factory FRet3.fromJson(Map<String, dynamic> json) => _$FRet3FromJson(json);

  Map<String, dynamic> toJson() => _$FRet3ToJson(this);
}
@JsonSerializable()
class FParam3 {
  FParam3(this.p0);

  MessageStatus p0;

  factory FParam3.fromJson(Map<String, dynamic> json) => _$FParam3FromJson(json);

  Map<String, dynamic> toJson() => _$FParam3ToJson(this);
}
@JsonSerializable()
class FParam4 {
  FParam4(this.p0);

  List<String> p0;

  factory FParam4.fromJson(Map<String, dynamic> json) => _$FParam4FromJson(json);

  Map<String, dynamic> toJson() => _$FParam4ToJson(this);
}
@JsonSerializable()
class FParam5 {
  FParam5(this.p0);

  List<String> p0;

  factory FParam5.fromJson(Map<String, dynamic> json) => _$FParam5FromJson(json);

  Map<String, dynamic> toJson() => _$FParam5ToJson(this);
}
@JsonSerializable()
class FParam6 {
  FParam6(this.p0);

  List<String> p0;

  factory FParam6.fromJson(Map<String, dynamic> json) => _$FParam6FromJson(json);

  Map<String, dynamic> toJson() => _$FParam6ToJson(this);
}
@JsonSerializable()
class FParam7 {
  FParam7(this.p0);

  List<String> p0;

  factory FParam7.fromJson(Map<String, dynamic> json) => _$FParam7FromJson(json);

  Map<String, dynamic> toJson() => _$FParam7ToJson(this);
}
@JsonSerializable()
class FParam8 {
  FParam8(this.p0);

  List<String> p0;

  factory FParam8.fromJson(Map<String, dynamic> json) => _$FParam8FromJson(json);

  Map<String, dynamic> toJson() => _$FParam8ToJson(this);
}
@JsonSerializable()
class FParam9 {
  FParam9(this.p0);

  List<String> p0;

  factory FParam9.fromJson(Map<String, dynamic> json) => _$FParam9FromJson(json);

  Map<String, dynamic> toJson() => _$FParam9ToJson(this);
}
@JsonSerializable()
class FParam10 {
  FParam10(this.p0);

  List<String> p0;

  factory FParam10.fromJson(Map<String, dynamic> json) => _$FParam10FromJson(json);

  Map<String, dynamic> toJson() => _$FParam10ToJson(this);
}
@JsonSerializable()
class FParam11 {
  FParam11(this.p0);

  List<String> p0;

  factory FParam11.fromJson(Map<String, dynamic> json) => _$FParam11FromJson(json);

  Map<String, dynamic> toJson() => _$FParam11ToJson(this);
}
@JsonSerializable()
class FParam12 {
  FParam12(this.p0);

  List<Object> p0;

  factory FParam12.fromJson(Map<String, dynamic> json) => _$FParam12FromJson(json);

  Map<String, dynamic> toJson() => _$FParam12ToJson(this);
}
@JsonSerializable()
class FParam13 {
  FParam13(this.p0);

  List<String> p0;

  factory FParam13.fromJson(Map<String, dynamic> json) => _$FParam13FromJson(json);

  Map<String, dynamic> toJson() => _$FParam13ToJson(this);
}
@JsonSerializable()
class FParam14 {
  FParam14(this.p0);

  List<Object> p0;

  factory FParam14.fromJson(Map<String, dynamic> json) => _$FParam14FromJson(json);

  Map<String, dynamic> toJson() => _$FParam14ToJson(this);
}
@JsonSerializable()
class FParam15 {
  FParam15(this.p0);

  Set<Object> p0;

  factory FParam15.fromJson(Map<String, dynamic> json) => _$FParam15FromJson(json);

  Map<String, dynamic> toJson() => _$FParam15ToJson(this);
}
@JsonSerializable()
class FParam16 {
  FParam16(this.p0);

  Set<Object> p0;

  factory FParam16.fromJson(Map<String, dynamic> json) => _$FParam16FromJson(json);

  Map<String, dynamic> toJson() => _$FParam16ToJson(this);
}
@JsonSerializable()
class FParam17 {
  FParam17(this.p0);

  Set<String> p0;

  factory FParam17.fromJson(Map<String, dynamic> json) => _$FParam17FromJson(json);

  Map<String, dynamic> toJson() => _$FParam17ToJson(this);
}
@JsonSerializable()
class FParam18 {
  FParam18(this.p0);

  Set<Object> p0;

  factory FParam18.fromJson(Map<String, dynamic> json) => _$FParam18FromJson(json);

  Map<String, dynamic> toJson() => _$FParam18ToJson(this);
}
@JsonSerializable()
class FParam19 {
  FParam19(this.p0);

  Set<String> p0;

  factory FParam19.fromJson(Map<String, dynamic> json) => _$FParam19FromJson(json);

  Map<String, dynamic> toJson() => _$FParam19ToJson(this);
}
@JsonSerializable()
class FParam20 {
  FParam20(this.p0);

  Set<String> p0;

  factory FParam20.fromJson(Map<String, dynamic> json) => _$FParam20FromJson(json);

  Map<String, dynamic> toJson() => _$FParam20ToJson(this);
}
@JsonSerializable()
class FParam21 {
  FParam21(this.p0);

  Map<String,String> p0;

  factory FParam21.fromJson(Map<String, dynamic> json) => _$FParam21FromJson(json);

  Map<String, dynamic> toJson() => _$FParam21ToJson(this);
}
@JsonSerializable()
class FParam22 {
  FParam22(this.p0);

  Map p0;

  factory FParam22.fromJson(Map<String, dynamic> json) => _$FParam22FromJson(json);

  Map<String, dynamic> toJson() => _$FParam22ToJson(this);
}
@JsonSerializable()
class FParam23 {
  FParam23(this.p0);

  Map<Object,String> p0;

  factory FParam23.fromJson(Map<String, dynamic> json) => _$FParam23FromJson(json);

  Map<String, dynamic> toJson() => _$FParam23ToJson(this);
}
@JsonSerializable()
class FParam24 {
  FParam24(this.p0);

  Map<Object,Object> p0;

  factory FParam24.fromJson(Map<String, dynamic> json) => _$FParam24FromJson(json);

  Map<String, dynamic> toJson() => _$FParam24ToJson(this);
}
@JsonSerializable()
class FParam25 {
  FParam25(this.p0);

  Map<Object,Object> p0;

  factory FParam25.fromJson(Map<String, dynamic> json) => _$FParam25FromJson(json);

  Map<String, dynamic> toJson() => _$FParam25ToJson(this);
}
@JsonSerializable()
class FParam26 {
  FParam26(this.p0);

  Map<Object,List<Map<String,String>>> p0;

  factory FParam26.fromJson(Map<String, dynamic> json) => _$FParam26FromJson(json);

  Map<String, dynamic> toJson() => _$FParam26ToJson(this);
}
@JsonSerializable()
class FParam27 {
  FParam27(this.p0);

  Map<String,String> p0;

  factory FParam27.fromJson(Map<String, dynamic> json) => _$FParam27FromJson(json);

  Map<String, dynamic> toJson() => _$FParam27ToJson(this);
}
@JsonSerializable()
class FParam28 {
  FParam28(this.p0);

  Map<String,String> p0;

  factory FParam28.fromJson(Map<String, dynamic> json) => _$FParam28FromJson(json);

  Map<String, dynamic> toJson() => _$FParam28ToJson(this);
}
@JsonSerializable()
class FParam29 {
  FParam29(this.p0);

  Map p0;

  factory FParam29.fromJson(Map<String, dynamic> json) => _$FParam29FromJson(json);

  Map<String, dynamic> toJson() => _$FParam29ToJson(this);
}
@JsonSerializable()
class FParam30 {
  FParam30(this.p0);

  UserInfo p0;

  factory FParam30.fromJson(Map<String, dynamic> json) => _$FParam30FromJson(json);

  Map<String, dynamic> toJson() => _$FParam30ToJson(this);
}
@JsonSerializable()
class FParam31 {
  FParam31(this.p0);

  User p0;

  factory FParam31.fromJson(Map<String, dynamic> json) => _$FParam31FromJson(json);

  Map<String, dynamic> toJson() => _$FParam31ToJson(this);
}
@JsonSerializable()
class FParam32 {
  FParam32(this.p0);

  AUser p0;

  factory FParam32.fromJson(Map<String, dynamic> json) => _$FParam32FromJson(json);

  Map<String, dynamic> toJson() => _$FParam32ToJson(this);
}
@JsonSerializable()
class FParam33 {
  FParam33(this.p0);

  User<String> p0;

  factory FParam33.fromJson(Map<String, dynamic> json) => _$FParam33FromJson(json);

  Map<String, dynamic> toJson() => _$FParam33ToJson(this);
}
@JsonSerializable()
class FRet34 {
  FRet34(this.ret);

  String ret;

  factory FRet34.fromJson(Map<String, dynamic> json) => _$FRet34FromJson(json);

  Map<String, dynamic> toJson() => _$FRet34ToJson(this);
}
@JsonSerializable()
class FRet35 {
  FRet35(this.ret);

  bool ret;

  factory FRet35.fromJson(Map<String, dynamic> json) => _$FRet35FromJson(json);

  Map<String, dynamic> toJson() => _$FRet35ToJson(this);
}
@JsonSerializable()
class FRet36 {
  FRet36(this.ret);

  int ret;

  factory FRet36.fromJson(Map<String, dynamic> json) => _$FRet36FromJson(json);

  Map<String, dynamic> toJson() => _$FRet36ToJson(this);
}
@JsonSerializable()
class FRet37 {
  FRet37(this.ret);

  int ret;

  factory FRet37.fromJson(Map<String, dynamic> json) => _$FRet37FromJson(json);

  Map<String, dynamic> toJson() => _$FRet37ToJson(this);
}
@JsonSerializable()
class FRet38 {
  FRet38(this.ret);

  int ret;

  factory FRet38.fromJson(Map<String, dynamic> json) => _$FRet38FromJson(json);

  Map<String, dynamic> toJson() => _$FRet38ToJson(this);
}
@JsonSerializable()
class FRet39 {
  FRet39(this.ret);

  int ret;

  factory FRet39.fromJson(Map<String, dynamic> json) => _$FRet39FromJson(json);

  Map<String, dynamic> toJson() => _$FRet39ToJson(this);
}
@JsonSerializable()
class FRet40 {
  FRet40(this.ret);

  int ret;

  factory FRet40.fromJson(Map<String, dynamic> json) => _$FRet40FromJson(json);

  Map<String, dynamic> toJson() => _$FRet40ToJson(this);
}
@JsonSerializable()
class FRet41 {
  FRet41(this.ret);

  bool ret;

  factory FRet41.fromJson(Map<String, dynamic> json) => _$FRet41FromJson(json);

  Map<String, dynamic> toJson() => _$FRet41ToJson(this);
}
@JsonSerializable()
class FRet42 {
  FRet42(this.ret);

  List<bool> ret;

  factory FRet42.fromJson(Map<String, dynamic> json) => _$FRet42FromJson(json);

  Map<String, dynamic> toJson() => _$FRet42ToJson(this);
}
@JsonSerializable()
class FRet43 {
  FRet43(this.ret);

  int ret;

  factory FRet43.fromJson(Map<String, dynamic> json) => _$FRet43FromJson(json);

  Map<String, dynamic> toJson() => _$FRet43ToJson(this);
}
@JsonSerializable()
class FRet44 {
  FRet44(this.ret);

  List<int> ret;

  factory FRet44.fromJson(Map<String, dynamic> json) => _$FRet44FromJson(json);

  Map<String, dynamic> toJson() => _$FRet44ToJson(this);
}
@JsonSerializable()
class FRet45 {
  FRet45(this.ret);

  int ret;

  factory FRet45.fromJson(Map<String, dynamic> json) => _$FRet45FromJson(json);

  Map<String, dynamic> toJson() => _$FRet45ToJson(this);
}
@JsonSerializable()
class FRet46 {
  FRet46(this.ret);

  List<int> ret;

  factory FRet46.fromJson(Map<String, dynamic> json) => _$FRet46FromJson(json);

  Map<String, dynamic> toJson() => _$FRet46ToJson(this);
}
@JsonSerializable()
class FRet47 {
  FRet47(this.ret);

  int ret;

  factory FRet47.fromJson(Map<String, dynamic> json) => _$FRet47FromJson(json);

  Map<String, dynamic> toJson() => _$FRet47ToJson(this);
}
@JsonSerializable()
class FRet48 {
  FRet48(this.ret);

  List<int> ret;

  factory FRet48.fromJson(Map<String, dynamic> json) => _$FRet48FromJson(json);

  Map<String, dynamic> toJson() => _$FRet48ToJson(this);
}
@JsonSerializable()
class FRet49 {
  FRet49(this.ret);

  int ret;

  factory FRet49.fromJson(Map<String, dynamic> json) => _$FRet49FromJson(json);

  Map<String, dynamic> toJson() => _$FRet49ToJson(this);
}
@JsonSerializable()
class FRet50 {
  FRet50(this.ret);

  List<int> ret;

  factory FRet50.fromJson(Map<String, dynamic> json) => _$FRet50FromJson(json);

  Map<String, dynamic> toJson() => _$FRet50ToJson(this);
}
@JsonSerializable()
class FRet51 {
  FRet51(this.ret);

  List<String> ret;

  factory FRet51.fromJson(Map<String, dynamic> json) => _$FRet51FromJson(json);

  Map<String, dynamic> toJson() => _$FRet51ToJson(this);
}
@JsonSerializable()
class FRet52 {
  FRet52(this.ret);

  List<String> ret;

  factory FRet52.fromJson(Map<String, dynamic> json) => _$FRet52FromJson(json);

  Map<String, dynamic> toJson() => _$FRet52ToJson(this);
}
@JsonSerializable()
class FParam53 {
  FParam53(this.p0, this.p1, this.p2, this.p3);

  String p0;
  int p1;
  Gender p2;
  Conversation p3;

  factory FParam53.fromJson(Map<String, dynamic> json) => _$FParam53FromJson(json);

  Map<String, dynamic> toJson() => _$FParam53ToJson(this);
}



<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example.bean/AUser.dart<|end_filename|>
import 'package:json_annotation/json_annotation.dart';
import "User.dart";

part 'AUser.g.dart';

@JsonSerializable()
class AUser extends User<String> {
  AUser();

  
  factory AUser.fromJson(Map<String, dynamic> json) => _$AUserFromJson(json);

  Map<String, dynamic> toJson() => _$AUserToJson(this);
}


<|start_filename|>fidl/example/android/app/src/main/java/com/infiniteloop/fidl_example/bean/MessageDirection.java<|end_filename|>
package com.infiniteloop.fidl_example.bean;

public enum MessageDirection {
    Send(0),
    Receive(1);

    private int value;

    MessageDirection(int value) {
        this.value = value;
    }

    public int value() {
        return this.value;
    }

    public static MessageDirection direction(int direction) {
        MessageDirection messageDirection = null;
        switch (direction) {
            case 0:
                messageDirection = Send;
                break;
            case 1:
                messageDirection = Receive;
                break;
            default:
                throw new IllegalArgumentException("direction " + direction + " is invalid");
        }
        return messageDirection;

    }
}


<|start_filename|>fidl/android/src/main/java/com/infiniteloop/fidl/JsonObjectCodec.java<|end_filename|>
package com.infiniteloop.fidl;

import com.jsoniter.JsonIterator;
import com.jsoniter.output.JsonStream;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

public class JsonObjectCodec implements ObjectCodec {
    public static final JsonObjectCodec INSTANCE = new JsonObjectCodec();
    private static final byte[] NULL = "\"null\"".getBytes();

    @Override
    public List<byte[]> encode(Object... objects) {
        List<byte[]> bytes = new ArrayList<>();
        if (objects == null || objects.length == 0) {
            bytes.add(NULL);
        } else {
            for (Object obj : objects) {
                if (obj == null) {
                    bytes.add(NULL);
                } else {
                    String json = JsonStream.serialize(obj);
                    LogUtils.d(json);
                    bytes.add(json.getBytes());
//                    ExposedByteArrayOutputStream outputStream = new ExposedByteArrayOutputStream();
//                    JsonStream.serialize(obj, outputStream);
//                    bytes.add(outputStream.buffer());
                }
            }
        }
        return bytes;
    }

    @Override
    public <T> T decode(byte[] input, TypeLiteral<T> type) {
        T ret = JsonIterator.deserialize(input, getRealType(type));
        LogUtils.d(ret);
        return ret;
    }

    private static <T> com.jsoniter.spi.TypeLiteral<T> getRealType(TypeLiteral<T> type) {
        return com.jsoniter.spi.TypeLiteral.create(type.getSuperclassTypeParameter());
    }
}


<|start_filename|>fidl/example/fidl/com.infiniteloop.fidl_example.bean.UiMessage.json<|end_filename|>
{"type":"com.infiniteloop.fidl_example.bean.UiMessage","kind":"class","fields":[{"name":"message","type":"com.infiniteloop.fidl_example.bean.Message"},{"name":"progress","type":"int"},{"name":"isChecked","type":"bool"},{"name":"isFocus","type":"bool"},{"name":"isDownloading","type":"bool"},{"name":"isPlaying","type":"bool"}],"superType":"?"}

<|start_filename|>fidl/example/android/app/src/main/java/com/infiniteloop/fidl_example/bean/UserInfo.java<|end_filename|>
package com.infiniteloop.fidl_example.bean;


public class UserInfo {
    public String uid;
    public String name;
    public int age;

    public UserInfo() {
    }

    public UserInfo(String uid, String name, int age) {
        this.uid = uid;
        this.name = name;
        this.age = age;
    }
}


<|start_filename|>fidl/android/src/main/java/com/infiniteloop/fidl/ExposedByteArrayOutputStream.java<|end_filename|>
package com.infiniteloop.fidl;

import java.io.ByteArrayOutputStream;

public final class ExposedByteArrayOutputStream extends ByteArrayOutputStream {
    byte[] buffer() {
        return buf;
    }
}

<|start_filename|>fidl/android/src/main/java/com/infiniteloop/fidl/FidlChannel.java<|end_filename|>
package com.infiniteloop.fidl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.EventChannel;

public final class FidlChannel {
    private Map<String, List<ChannelConnection>> map;
    private static FidlChannel instance = Holder.instance;
    public static ObjectCodec objectCodec = JsonObjectCodec.INSTANCE;

    private FidlChannel() {
        map = new HashMap<>();
    }

    private static class Holder {
        private static final FidlChannel instance = new FidlChannel();
    }

    public static void registerObjectCodec(ObjectCodec codec) {
        if (codec != null) {
            objectCodec = codec;
        }
    }

    static boolean bindChannel(BinaryMessenger messenger, String channelName, int connectionCode) {
        if (!instance.map.containsKey(channelName)) {
            return false;
        }
        List<ChannelConnection> list = instance.map.get(channelName);
        if (list == null) {
            list = new ArrayList<>();
        }
        list.add(new ChannelConnection(messenger, channelName, connectionCode));
        return true;
    }

    private static final class ChannelConnection {
        EventChannel.EventSink eventSink;
        int connectionCode;

        ChannelConnection(BinaryMessenger messenger, String channelName, int connectionCode) {
            this.connectionCode = connectionCode;
            String eventChannelName = channelName + connectionCode;
            new EventChannel(messenger, eventChannelName).setStreamHandler(new EventChannel.StreamHandler() {
                @Override
                public void onListen(Object arguments, EventChannel.EventSink events) {
                    eventSink = events;
                    eventSink.success(true);
                }

                @Override
                public void onCancel(Object arguments) {
                    eventSink.success(false);
                }
            });
        }
    }

    static void unbindChannel(String channelName, int connectionCode) {
        if (!instance.map.containsKey(channelName)) {
            return;
        }
        List<ChannelConnection> list = instance.map.get(channelName);
        if (list != null && list.size() > 0) {
            Iterator<ChannelConnection> it = list.iterator();
            while (it.hasNext()) {
                ChannelConnection connection = it.next();
                if (connection.connectionCode == connectionCode) {
                    if (connection.eventSink != null) {
                        connection.eventSink.success(false);
                    }
                    it.remove();
                }
            }
        }
    }

    public static void openChannel(BinaryMessenger messenger, Channel channel) {
        if (channel != null && messenger != null) {
            instance.map.put(channel.getChannelName(), new ArrayList<ChannelConnection>());
            channel.attachMethodChannel(messenger);
        }
    }

    public static void closeChannel(Channel channel) {
        channel.detachMethodChannel();
        if (!instance.map.containsKey(channel.getChannelName())) {
            return;
        }
        List<ChannelConnection> list = instance.map.get(channel.getChannelName());
        if (list != null && list.size() > 0) {
            for (ChannelConnection connection : list) {
                if (connection.eventSink != null) {
                    connection.eventSink.success(false);
                }
            }
            list.clear();
        }
        instance.map.remove(channel.getChannelName());
    }
}


<|start_filename|>fidl/example/android/app/src/main/java/com/infiniteloop/fidl_example/bean/MessageContent.java<|end_filename|>
package com.infiniteloop.fidl_example.bean;

import android.os.Parcel;
import android.os.Parcelable;

import java.util.List;

public abstract class MessageContent implements Parcelable {
    //0 普通消息, 1 部分提醒, 2 提醒全部
    public int mentionedType;

    //提醒对象，mentionedType 1时有效
    public List<String> mentionedTargets;
    public String extra;
    public String pushContent;

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(this.mentionedType);
        dest.writeStringList(this.mentionedTargets);
        dest.writeString(this.extra);
        dest.writeString(this.pushContent);
    }

    public MessageContent() {
    }

    protected MessageContent(Parcel in) {
        this.mentionedType = in.readInt();
        this.mentionedTargets = in.createStringArrayList();
        this.extra = in.readString();
        this.pushContent = in.readString();
    }
}


<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example.bean/UiMessage.dart<|end_filename|>
import 'package:json_annotation/json_annotation.dart';
import "Message.dart";

part 'UiMessage.g.dart';

@JsonSerializable()
class UiMessage extends Object {
  UiMessage();

  Message message;
  int progress;
  bool isChecked;
  bool isFocus;
  bool isDownloading;
  bool isPlaying;
  
  factory UiMessage.fromJson(Map<String, dynamic> json) => _$UiMessageFromJson(json);

  Map<String, dynamic> toJson() => _$UiMessageToJson(this);
}


<|start_filename|>fidl/example/fidl/com.infiniteloop.fidl_example.bean.Conversation.ConversationType.json<|end_filename|>
{"type":"com.infiniteloop.fidl_example.bean.Conversation.ConversationType(Channel,ChatRoom,Group,Single)","kind":"enum","fields":[{"name":"value","type":"int"}],"superType":""}

<|start_filename|>fidl/example/android/fidlprocessor/src/test/java/com/infinateloop/fidl/MethodCall.java<|end_filename|>
package com.infinateloop.fidl;

public class MethodCall {
}


<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example.bean/MessageContent.g.dart<|end_filename|>
// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'MessageContent.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

MessageContent _$MessageContentFromJson(Map<String, dynamic> json) {
  return MessageContent()
    ..pushContent = json['pushContent'] as String
    ..extra = json['extra'] as String
    ..mentionedTargets =
        (json['mentionedTargets'] as List)?.map((e) => e as String)?.toList()
    ..mentionedType = json['mentionedType'] as int;
}

Map<String, dynamic> _$MessageContentToJson(MessageContent instance) =>
    <String, dynamic>{
      'pushContent': instance.pushContent,
      'extra': instance.extra,
      'mentionedTargets': instance.mentionedTargets,
      'mentionedType': instance.mentionedType,
    };


<|start_filename|>fidl/example/fidl/com.infiniteloop.fidl_example.bean.Conversation.json<|end_filename|>
{"type":"com.infiniteloop.fidl_example.bean.Conversation","kind":"class","fields":[{"name":"target","type":"String"},{"name":"type","type":"com.infiniteloop.fidl_example.bean.Conversation.ConversationType"}],"superType":"?"}

<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example.bean.Conversation/ConversationType.dart<|end_filename|>
enum ConversationType {
  Channel,
  ChatRoom,
  Group,
  Single,
}


<|start_filename|>fidl/lib/fidl.dart<|end_filename|>
import 'dart:async';
import 'dart:typed_data';

import 'package:flutter/services.dart';
import 'dart:convert';

import 'package:json_annotation/json_annotation.dart';
export 'multi_message_codec.dart';
export 'type_util.dart';

class Fidl {
  static const MethodChannel _channel = const MethodChannel('fidl');
  static ObjectCodec objectCodec = JsonObjectCodec();

  static Future<String> get platformVersion async {
    final String version = await _channel.invokeMethod('getPlatformVersion');
    return version;
  }

  static Future<bool> bindChannel(
      String channelName, ChannelConnection conn) async {
    // TODO conn 回调监听
    final bool success = await _channel
        .invokeMethod('bind', {'name': channelName, 'code': conn.hashCode});

    String name = '$channelName${conn.hashCode}';
    EventChannel(name).receiveBroadcastStream().listen((data) {
      if (data is bool) {
        conn.connected = data;
        if (data) {
          conn.onConnected();
        } else {
          conn.onDisconnected();
        }
      }
    });
    return success;
  }

  static Future<void> unbindChannel(
      String channelName, ChannelConnection conn) async {
    await _channel
        .invokeMethod('unbind', {'name': channelName, 'code': conn.hashCode});
  }
}

typedef void OnConnectedCallback();
typedef void OnDisconnectedCallback();

class ChannelConnection {
  bool connected = false;

  OnConnectedCallback onConnected;
  OnDisconnectedCallback onDisconnected;

  ChannelConnection(this.onConnected, this.onDisconnected);
}

abstract class ObjectCodec {
  dynamic decode(Uint8List input);

  List<Uint8List> encode(List objects);
}

class JsonObjectCodec extends ObjectCodec {
  @override
  decode(Uint8List input) {
    return jsonDecode(utf8.decode(input));
  }

  @override
  List<Uint8List> encode(List objects) {
    List<Uint8List> list = [];
    objects.forEach((object) {
      list.add(
          utf8.encoder.convert(jsonEncode(object, toEncodable: toEncodable)));
    });
    return list;
  }

  static Object toEncodable(Object nonEncodable) {
    try {
      return (nonEncodable as dynamic).toJson();
    } catch (ex) {}
    return 'unknown';
  }
}

class GenericConverter<T> implements JsonConverter<T, Object> {
  const GenericConverter();

  @override
  T fromJson(Object json) {
    return json;
  }

  @override
  Object toJson(T object) {
    return object;
  }
}


<|start_filename|>fidl/example/lib/chat_screen.dart<|end_filename|>
import 'package:fidl_example/fidl/com.infiniteloop.fidl_example.bean.Conversation/ConversationType.dart';
import 'package:fidl_example/fidl/com.infiniteloop.fidl_example.bean/Conversation.dart';
import 'package:fidl_example/fidl/com.infiniteloop.fidl_example.bean/MessageDirection.dart';
import 'package:fidl_example/fidl/com.infiniteloop.fidl_example.bean/UiMessage.dart';
import 'package:fidl_example/fidl/com.infiniteloop.fidl_example/IConversationService.dart';
import 'package:fidl_example/shape_button.dart';
import 'package:flutter/material.dart';
import 'package:fidl/fidl.dart';
import 'package:fluttertoast/fluttertoast.dart';

class ChatScreen extends StatefulWidget {
  @override
  _ChatScreenState createState() => _ChatScreenState();
}

class _ChatScreenState extends State<ChatScreen> {
  ChannelConnection _conversationConnection;
  Conversation _conversation;
  String partnerName = 'Amy';

  @override
  void initState() {
    super.initState();
    _conversationConnection = ChannelConnection(() {
      print('Conversation Service onConnected');
    }, () {
      print('Conversation Service onDisconnected');
    });

    _conversation = Conversation();
    _conversation.target = '0';
    _conversation.type = ConversationType.Single;

    initConversationService();
  }

  Future<void> initConversationService() async {
    await Fidl.bindChannel(
        IConversationService.CHANNEL_NAME, _conversationConnection);
  }

  @override
  void dispose() {
    super.dispose();
    Fidl.unbindChannel(
        IConversationService.CHANNEL_NAME, _conversationConnection);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: new AppBar(
        title: new Text('Chat'),
      ),
      body: Builder(
        builder: (context) => Center(
            child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Choose someone to chat'),
            SizedBox(height: 4),
            ShapeButton(
                onPressed: () async {
                  setState(() {
                    partnerName = 'Amy';
                  });
                  await showConversationDesc('10');
                },
                child: Text('Chat with Amy')),
            ShapeButton(
                onPressed: () async {
                  setState(() {
                    partnerName = 'Wilson';
                  });
                  await showConversationDesc('11');
                },
                child: Text('Chat with Wilson')),
            ShapeButton(
                onPressed: () async {
                  setState(() {
                    partnerName = 'Lucy';
                  });
                  await showConversationDesc('12');
                },
                child: Text('Chat with Lucy')),
            SizedBox(height: 20),
            Text('Click the buttons below one by one'),
            SizedBox(height: 4),
            ShapeButton(
                onPressed: () async {
                  List<UiMessage> messages =
                      await IConversationService.getMessages();
                  print(messages.length);
                  print(messages);

                  List<Widget> widgets = [];
                  messages.forEach((uiMessage) {
                    if (uiMessage.message.direction == MessageDirection.Send) {
                      widgets.add(Padding(
                          padding: const EdgeInsets.symmetric(vertical: 3),
                          child: Text(
                              'Oscar: ${uiMessage.message.content.extra}')));
                    } else {
                      widgets.add(Padding(
                          padding: const EdgeInsets.symmetric(vertical: 3),
                          child: Text(
                              '$partnerName: ${uiMessage.message.content.extra}')));
                    }
                  });

                  showDialog(
                      context: context,
                      builder: (_) => AlertDialog(
                              title: Text(
                                  'Messages with $partnerName'),
                              content: SingleChildScrollView(
                                  child: ListBody(
                                children: widgets,
                              )),
                              actions: <Widget>[
                                FlatButton(
                                    child: const Text('OK'),
                                    onPressed: () {
                                      Navigator.of(context).pop(true);
                                    })
                              ]));
                },
                child: Text('Get history messages')),
            ShapeButton(
                onPressed: () async {
                  await IConversationService.sendMessage('Hello from flutter!');
                  Fluttertoast.showToast(msg: 'Done!');
                },
                child: Text('Send a message')),
            ShapeButton(
                onPressed: () async {
                  int count = await IConversationService.getMessageCount();
                  showDialog(
                      context: context,
                      builder: (_) => AlertDialog(
                              title: Text('Message count is:'),
                              content: Text('$count'),
                              actions: <Widget>[
                                FlatButton(
                                    child: const Text('OK'),
                                    onPressed: () {
                                      Navigator.of(context).pop(true);
                                    })
                              ]));
                },
                child: Text('Get the number of messages'))
          ],
        )),
      ),
    );
  }

  Future<void> showConversationDesc(String targetUid) async {
    Conversation conversation = Conversation();
    conversation.target = targetUid;
    conversation.type = ConversationType.Single;
    setState(() {
      _conversation = conversation;
    });

    await IConversationService.setupConversation(conversation);
    String conversationDesc = await IConversationService.getConversationDesc();
    showDialog<bool>(
        context: context,
        builder: (_) => AlertDialog(
                title: Text('Conversation Description'),
                content: Text(conversationDesc),
                actions: <Widget>[
                  FlatButton(
                      child: const Text('OK'),
                      onPressed: () {
                        Navigator.of(context).pop(true);
                      })
                ]));
  }
}


<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example.bean/UserInfo.dart<|end_filename|>
import 'package:json_annotation/json_annotation.dart';

part 'UserInfo.g.dart';

@JsonSerializable()
class UserInfo extends Object {
  UserInfo();

  int age;
  String name;
  String uid;
  
  factory UserInfo.fromJson(Map<String, dynamic> json) => _$UserInfoFromJson(json);

  Map<String, dynamic> toJson() => _$UserInfoToJson(this);
}


<|start_filename|>fidl/example/android/app/src/main/java/com/infiniteloop/fidl_example/bean/EmptyEnum.java<|end_filename|>
package com.infiniteloop.fidl_example.bean;

public enum EmptyEnum {
}


<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example.bean/MessageStatus.dart<|end_filename|>
enum MessageStatus {
  Played,
  Readed,
  Unread,
  AllMentioned,
  Mentioned,
  Send_Failure,
  Sent,
  Sending,
}


<|start_filename|>fidl/example/android/fidlprocessor/src/main/java/com/infinateloop/fidlprocessor/AnnotatedClass.java<|end_filename|>
package com.infinateloop.fidlprocessor;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.sun.tools.javac.code.Type;

import java.util.List;

import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.util.Elements;

public class AnnotatedClass {

    public TypeElement mClassElement;
    public Elements mElementUtils;
    public FidlStructure structure;

    public AnnotatedClass(TypeElement classElement, Elements elementUtils, FidlStructure structure) {
        this.mClassElement = classElement;
        this.mElementUtils = elementUtils;
        this.structure = structure;
    }

    //获取包名
    public String getPackageName(TypeElement type) {
        return mElementUtils.getPackageOf(type).getQualifiedName().toString();
    }

    //获取类名
    private static String getClassName(TypeElement type, String packageName) {
        int packageLen = packageName.length() + 1;
        return type.getQualifiedName().toString().substring(packageLen).replace('.', '$');
    }

    public JavaFile generateFidlStubClass() throws Exception {
        String packageName = getPackageName(mClassElement);
        String className = getClassName(mClassElement, packageName);

        ClassName interfaceClassName = ClassName.get(packageName, className);

        List<FidlStructure.Method> methods = structure.methods;
        CodeBlock.Builder blockBuilder = CodeBlock.builder();
        if (methods.size() > 0) {
            generateFidlStubCodeBlock(methods, blockBuilder);
        }

        // Stub 类继承 Channel 类，实现其中的 getChannelName 和 onMethodCall方法
        TypeSpec channelClass = TypeSpec.classBuilder(interfaceClassName.simpleName() + "Stub")
                .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
                .superclass(ClassName.bestGuess("com.infiniteloop.fidl.Channel"))
                .addSuperinterface(ParameterizedTypeName.get(mClassElement.asType()))

                .addField(FieldSpec.builder(String.class, "CHANNEL_NAME", Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
                        .initializer("\"$L\"", interfaceClassName.canonicalName()).build())

                .addMethod(MethodSpec.methodBuilder("getChannelName")
                        .addAnnotation(Override.class)
                        .addModifiers(Modifier.PUBLIC).returns(String.class)
                        .addStatement("return CHANNEL_NAME").build())

                .addMethod(MethodSpec.methodBuilder("onMethodCall")
                        .addAnnotation(Override.class)
                        .addModifiers(Modifier.PUBLIC)
                        .addParameter(TypeName.get(String.class), "method")
                        .addParameter(ParameterizedTypeName.get(List.class, byte[].class), "arguments")
                        .returns(TypeName.OBJECT)
                        .addCode(blockBuilder.build())
                        .addStatement("return null").build())
                .build();


        JavaFile javaFile = JavaFile.builder(packageName, channelClass).build();
//        try {
//            javaFile.writeTo(System.out);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
        return javaFile;
    }

    /**
     * 解析FIDL接口中的方法，生成解析参数和返回值的代码
     * 例如：
     * if(method.equals("setupConversation")) {
     * Conversation p0 = FidlChannel.objectCodec.decode(arguments.get(0),new TypeLiteral<Conversation>(){});
     * setupConversation(p0);
     * return null;
     * }
     * if(method.equals("getConversationDesc")) {
     * String ret = getConversationDesc();
     * return ret;
     * }
     */
    private void generateFidlStubCodeBlock(List<FidlStructure.Method> methods, CodeBlock.Builder builder) {
        for (FidlStructure.Method method : methods) {
            ClassName clsFidlChannel = ClassName.bestGuess("com.infiniteloop.fidl.FidlChannel");
            ClassName clsTypeLiteral = ClassName.bestGuess("com.infiniteloop.fidl.TypeLiteral");

            builder.beginControlFlow("if(method.equals(\"$L\"))", method.name);
            List<FidlStructure.Parameter> parameterTypes = method.parameters;

            Type returnType = method.returns;
            if (parameterTypes.size() > 0) {
                for (int i = 0; i < method.parameters.size(); i++) {
                    Type paramType = parameterTypes.get(i).type;
                    // 参数类型判断
                    builder.addStatement("$T p$L = $T.objectCodec.decode(arguments.get($L),new $T<$T>(){})", paramType, i, clsFidlChannel, i, clsTypeLiteral, paramType);
                }
            }

            if (returnType.getKind() == TypeKind.VOID) {
                builder.add("$L(", method.name);
            } else {
                builder.add("$T ret = $L(", returnType, method.name);
            }
            for (int i = 0; i < parameterTypes.size(); i++) {
                if (i == parameterTypes.size() - 1) {
                    builder.add("p$L", i);
                } else {
                    builder.add("p$L, ", i);
                }
            }
            builder.add(");\n");

            if (returnType.getKind() != TypeKind.VOID) {
                builder.addStatement("return ret");
            } else {
                builder.addStatement("return null");
            }
            builder.endControlFlow();
        }
    }
}

<|start_filename|>fidl/example/android/fidlprocessor/src/test/java/com/infinateloop/fidl/JsonStreamTest.java<|end_filename|>
package com.infinateloop.fidl;

import com.jsoniter.JsonIterator;
import com.jsoniter.output.JsonStream;
import com.jsoniter.spi.TypeLiteral;

import org.junit.Test;

import java.util.PriorityQueue;
import java.util.Queue;

public class JsonStreamTest {
    @Test
    public void charObj() {
        class Char {
            char a = 'x';
            char b = 'y';
        }
        System.out.println(JsonStream.serialize(new Char()));
    }

    @Test
    public void voidObj() {
        class VO {
            Void a = null;
            Void b = null;
        }
        System.out.println(JsonStream.serialize(new VO()));
    }

    @Test
    public void arrayObj() {
        class AO {
            String[] a = new String[]{"x", "y"};
        }
        System.out.println(JsonStream.serialize(new AO()));
    }

    @Test
    public void dynamicParams() {
        test();
        test(null);
        test((Object) null);
        test(null, null);
        System.out.println(JsonIterator.deserialize((String) "null", Object.class));
    }

    private void test(Object... objects) {
        if (objects == null) {
            System.out.println("null");
            return;
        }
        System.out.println(objects.length);
    }

    enum E {
        A(0), B(3), C(4);
        int value;

        E(int i) {
            value = i;
        }
    }

    @Test
    public void enumObj() {
        class EO {
            E a = E.A;
        }
        System.out.println(JsonStream.serialize(new EO()));
    }

    static class EO {
        MessageStatus status = MessageStatus.AllMentioned;
    }

    @Test
    public void enumObj1() {
        EO obj = new EO();
        String json = JsonStream.serialize(obj);
        System.out.println(json);
        EO obj1 = JsonIterator.deserialize(json, EO.class);
        System.out.println(obj1.status);
    }

    @Test
    public void streamQueue() {
        Queue<Object> queue = new PriorityQueue<>();
        queue.offer("1");
        queue.offer("a");
        queue.offer("E.B");
        System.out.println(JsonStream.serialize(queue));
    }

    @Test
    public void streamUserInfo() {
        UserInfo info = new UserInfo("","",1);
        info.age = 16;
        System.out.println(JsonStream.serialize(info));
    }

    @Test
    public void deserializeUserInfo() {
        String json = "{\"age\":16,\"name\":null,\"uid\":null}";
        UserInfo info = JsonIterator.deserialize(json, new TypeLiteral<UserInfo>(){});
        System.out.println(info.age);
    }
}


<|start_filename|>fidl/example/android/fidlprocessor/src/test/java/com/infinateloop/fidl/FlutterPlugin.java<|end_filename|>
package com.infinateloop.fidl;

public class FlutterPlugin {
    public interface MethodCallHandler {
        void onMethodCall(MethodCall call, Result result);
    }

    public static class Result {
    }
}


<|start_filename|>fidl/example/android/fidlprocessor/src/test/java/com/infinateloop/fidl/IUserService.java<|end_filename|>
package com.infinateloop.fidl;

import java.util.List;

public interface IUserService {
    void work(int x, double y,List<FlutterPlugin> plugin);
    List<FlutterPlugin> sleep();
}


<|start_filename|>fidl/example/fidl/com.infiniteloop.fidl_example.bean.Message.json<|end_filename|>
{"type":"com.infiniteloop.fidl_example.bean.Message","kind":"class","fields":[{"name":"serverTime","type":"long"},{"name":"messageUid","type":"long"},{"name":"status","type":"com.infiniteloop.fidl_example.bean.MessageStatus"},{"name":"direction","type":"com.infiniteloop.fidl_example.bean.MessageDirection"},{"name":"content","type":"com.infiniteloop.fidl_example.bean.MessageContent"},{"name":"toUsers","type":"@list(String)"},{"name":"sender","type":"String"},{"name":"conversation","type":"com.infiniteloop.fidl_example.bean.Conversation"},{"name":"messageId","type":"long"}],"superType":"?"}

<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example.bean/Conversation.dart<|end_filename|>
import 'package:json_annotation/json_annotation.dart';
import "../com.infiniteloop.fidl_example.bean.Conversation/ConversationType.dart";

part 'Conversation.g.dart';

@JsonSerializable()
class Conversation extends Object {
  Conversation();

  String target;
  ConversationType type;
  
  factory Conversation.fromJson(Map<String, dynamic> json) => _$ConversationFromJson(json);

  Map<String, dynamic> toJson() => _$ConversationToJson(this);
}


<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example/IUserService.g.dart<|end_filename|>
// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'IUserService.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

FParam0 _$FParam0FromJson(Map<String, dynamic> json) {
  return FParam0(
    (json['p0'] as List)?.map((e) => e as int)?.toList(),
  );
}

Map<String, dynamic> _$FParam0ToJson(FParam0 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam1 _$FParam1FromJson(Map<String, dynamic> json) {
  return FParam1(
    (json['p0'] as List)
        ?.map((e) => (e as List)?.map((e) => e as int)?.toList())
        ?.toList(),
  );
}

Map<String, dynamic> _$FParam1ToJson(FParam1 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam2 _$FParam2FromJson(Map<String, dynamic> json) {
  return FParam2(
    _$enumDecodeNullable(_$EmptyEnumEnumMap, json['p0']),
  );
}

Map<String, dynamic> _$FParam2ToJson(FParam2 instance) => <String, dynamic>{
      'p0': _$EmptyEnumEnumMap[instance.p0],
    };

T _$enumDecode<T>(
  Map<T, dynamic> enumValues,
  dynamic source, {
  T unknownValue,
}) {
  if (source == null) {
    throw ArgumentError('A value must be provided. Supported values: '
        '${enumValues.values.join(', ')}');
  }

  final value = enumValues.entries
      .singleWhere((e) => e.value == source, orElse: () => null)
      ?.key;

  if (value == null && unknownValue == null) {
    throw ArgumentError('`$source` is not one of the supported values: '
        '${enumValues.values.join(', ')}');
  }
  return value ?? unknownValue;
}

T _$enumDecodeNullable<T>(
  Map<T, dynamic> enumValues,
  dynamic source, {
  T unknownValue,
}) {
  if (source == null) {
    return null;
  }
  return _$enumDecode<T>(enumValues, source, unknownValue: unknownValue);
}

const _$EmptyEnumEnumMap = {
  EmptyEnum.none: 'none',
};

FRet3 _$FRet3FromJson(Map<String, dynamic> json) {
  return FRet3(
    json['ret'] as String,
  );
}

Map<String, dynamic> _$FRet3ToJson(FRet3 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FParam3 _$FParam3FromJson(Map<String, dynamic> json) {
  return FParam3(
    _$enumDecodeNullable(_$MessageStatusEnumMap, json['p0']),
  );
}

Map<String, dynamic> _$FParam3ToJson(FParam3 instance) => <String, dynamic>{
      'p0': _$MessageStatusEnumMap[instance.p0],
    };

const _$MessageStatusEnumMap = {
  MessageStatus.Played: 'Played',
  MessageStatus.Readed: 'Readed',
  MessageStatus.Unread: 'Unread',
  MessageStatus.AllMentioned: 'AllMentioned',
  MessageStatus.Mentioned: 'Mentioned',
  MessageStatus.Send_Failure: 'Send_Failure',
  MessageStatus.Sent: 'Sent',
  MessageStatus.Sending: 'Sending',
};

FParam4 _$FParam4FromJson(Map<String, dynamic> json) {
  return FParam4(
    (json['p0'] as List)?.map((e) => e as String)?.toList(),
  );
}

Map<String, dynamic> _$FParam4ToJson(FParam4 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam5 _$FParam5FromJson(Map<String, dynamic> json) {
  return FParam5(
    (json['p0'] as List)?.map((e) => e as String)?.toList(),
  );
}

Map<String, dynamic> _$FParam5ToJson(FParam5 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam6 _$FParam6FromJson(Map<String, dynamic> json) {
  return FParam6(
    (json['p0'] as List)?.map((e) => e as String)?.toList(),
  );
}

Map<String, dynamic> _$FParam6ToJson(FParam6 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam7 _$FParam7FromJson(Map<String, dynamic> json) {
  return FParam7(
    (json['p0'] as List)?.map((e) => e as String)?.toList(),
  );
}

Map<String, dynamic> _$FParam7ToJson(FParam7 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam8 _$FParam8FromJson(Map<String, dynamic> json) {
  return FParam8(
    (json['p0'] as List)?.map((e) => e as String)?.toList(),
  );
}

Map<String, dynamic> _$FParam8ToJson(FParam8 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam9 _$FParam9FromJson(Map<String, dynamic> json) {
  return FParam9(
    (json['p0'] as List)?.map((e) => e as String)?.toList(),
  );
}

Map<String, dynamic> _$FParam9ToJson(FParam9 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam10 _$FParam10FromJson(Map<String, dynamic> json) {
  return FParam10(
    (json['p0'] as List)?.map((e) => e as String)?.toList(),
  );
}

Map<String, dynamic> _$FParam10ToJson(FParam10 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam11 _$FParam11FromJson(Map<String, dynamic> json) {
  return FParam11(
    (json['p0'] as List)?.map((e) => e as String)?.toList(),
  );
}

Map<String, dynamic> _$FParam11ToJson(FParam11 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam12 _$FParam12FromJson(Map<String, dynamic> json) {
  return FParam12(
    json['p0'] as List,
  );
}

Map<String, dynamic> _$FParam12ToJson(FParam12 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam13 _$FParam13FromJson(Map<String, dynamic> json) {
  return FParam13(
    (json['p0'] as List)?.map((e) => e as String)?.toList(),
  );
}

Map<String, dynamic> _$FParam13ToJson(FParam13 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam14 _$FParam14FromJson(Map<String, dynamic> json) {
  return FParam14(
    json['p0'] as List,
  );
}

Map<String, dynamic> _$FParam14ToJson(FParam14 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam15 _$FParam15FromJson(Map<String, dynamic> json) {
  return FParam15(
    (json['p0'] as List)?.toSet(),
  );
}

Map<String, dynamic> _$FParam15ToJson(FParam15 instance) => <String, dynamic>{
      'p0': instance.p0?.toList(),
    };

FParam16 _$FParam16FromJson(Map<String, dynamic> json) {
  return FParam16(
    (json['p0'] as List)?.toSet(),
  );
}

Map<String, dynamic> _$FParam16ToJson(FParam16 instance) => <String, dynamic>{
      'p0': instance.p0?.toList(),
    };

FParam17 _$FParam17FromJson(Map<String, dynamic> json) {
  return FParam17(
    (json['p0'] as List)?.map((e) => e as String)?.toSet(),
  );
}

Map<String, dynamic> _$FParam17ToJson(FParam17 instance) => <String, dynamic>{
      'p0': instance.p0?.toList(),
    };

FParam18 _$FParam18FromJson(Map<String, dynamic> json) {
  return FParam18(
    (json['p0'] as List)?.toSet(),
  );
}

Map<String, dynamic> _$FParam18ToJson(FParam18 instance) => <String, dynamic>{
      'p0': instance.p0?.toList(),
    };

FParam19 _$FParam19FromJson(Map<String, dynamic> json) {
  return FParam19(
    (json['p0'] as List)?.map((e) => e as String)?.toSet(),
  );
}

Map<String, dynamic> _$FParam19ToJson(FParam19 instance) => <String, dynamic>{
      'p0': instance.p0?.toList(),
    };

FParam20 _$FParam20FromJson(Map<String, dynamic> json) {
  return FParam20(
    (json['p0'] as List)?.map((e) => e as String)?.toSet(),
  );
}

Map<String, dynamic> _$FParam20ToJson(FParam20 instance) => <String, dynamic>{
      'p0': instance.p0?.toList(),
    };

FParam21 _$FParam21FromJson(Map<String, dynamic> json) {
  return FParam21(
    (json['p0'] as Map<String, dynamic>)?.map(
      (k, e) => MapEntry(k, e as String),
    ),
  );
}

Map<String, dynamic> _$FParam21ToJson(FParam21 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam22 _$FParam22FromJson(Map<String, dynamic> json) {
  return FParam22(
    json['p0'] as Map<String, dynamic>,
  );
}

Map<String, dynamic> _$FParam22ToJson(FParam22 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam23 _$FParam23FromJson(Map<String, dynamic> json) {
  return FParam23(
    (json['p0'] as Map<String, dynamic>)?.map(
      (k, e) => MapEntry(k, e as String),
    ),
  );
}

Map<String, dynamic> _$FParam23ToJson(FParam23 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam24 _$FParam24FromJson(Map<String, dynamic> json) {
  return FParam24(
    json['p0'] as Map<String, dynamic>,
  );
}

Map<String, dynamic> _$FParam24ToJson(FParam24 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam25 _$FParam25FromJson(Map<String, dynamic> json) {
  return FParam25(
    json['p0'] as Map<String, dynamic>,
  );
}

Map<String, dynamic> _$FParam25ToJson(FParam25 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam26 _$FParam26FromJson(Map<String, dynamic> json) {
  return FParam26(
    (json['p0'] as Map<String, dynamic>)?.map(
      (k, e) => MapEntry(
          k,
          (e as List)
              ?.map((e) => (e as Map<String, dynamic>)?.map(
                    (k, e) => MapEntry(k, e as String),
                  ))
              ?.toList()),
    ),
  );
}

Map<String, dynamic> _$FParam26ToJson(FParam26 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam27 _$FParam27FromJson(Map<String, dynamic> json) {
  return FParam27(
    (json['p0'] as Map<String, dynamic>)?.map(
      (k, e) => MapEntry(k, e as String),
    ),
  );
}

Map<String, dynamic> _$FParam27ToJson(FParam27 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam28 _$FParam28FromJson(Map<String, dynamic> json) {
  return FParam28(
    (json['p0'] as Map<String, dynamic>)?.map(
      (k, e) => MapEntry(k, e as String),
    ),
  );
}

Map<String, dynamic> _$FParam28ToJson(FParam28 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam29 _$FParam29FromJson(Map<String, dynamic> json) {
  return FParam29(
    json['p0'] as Map<String, dynamic>,
  );
}

Map<String, dynamic> _$FParam29ToJson(FParam29 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam30 _$FParam30FromJson(Map<String, dynamic> json) {
  return FParam30(
    json['p0'] == null
        ? null
        : UserInfo.fromJson(json['p0'] as Map<String, dynamic>),
  );
}

Map<String, dynamic> _$FParam30ToJson(FParam30 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam31 _$FParam31FromJson(Map<String, dynamic> json) {
  return FParam31(
    json['p0'] == null
        ? null
        : User.fromJson(json['p0'] as Map<String, dynamic>),
  );
}

Map<String, dynamic> _$FParam31ToJson(FParam31 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam32 _$FParam32FromJson(Map<String, dynamic> json) {
  return FParam32(
    json['p0'] == null
        ? null
        : AUser.fromJson(json['p0'] as Map<String, dynamic>),
  );
}

Map<String, dynamic> _$FParam32ToJson(FParam32 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FParam33 _$FParam33FromJson(Map<String, dynamic> json) {
  return FParam33(
    json['p0'] == null
        ? null
        : User.fromJson(json['p0'] as Map<String, dynamic>),
  );
}

Map<String, dynamic> _$FParam33ToJson(FParam33 instance) => <String, dynamic>{
      'p0': instance.p0,
    };

FRet34 _$FRet34FromJson(Map<String, dynamic> json) {
  return FRet34(
    json['ret'] as String,
  );
}

Map<String, dynamic> _$FRet34ToJson(FRet34 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FRet35 _$FRet35FromJson(Map<String, dynamic> json) {
  return FRet35(
    json['ret'] as bool,
  );
}

Map<String, dynamic> _$FRet35ToJson(FRet35 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FRet36 _$FRet36FromJson(Map<String, dynamic> json) {
  return FRet36(
    json['ret'] as int,
  );
}

Map<String, dynamic> _$FRet36ToJson(FRet36 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FRet37 _$FRet37FromJson(Map<String, dynamic> json) {
  return FRet37(
    json['ret'] as int,
  );
}

Map<String, dynamic> _$FRet37ToJson(FRet37 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FRet38 _$FRet38FromJson(Map<String, dynamic> json) {
  return FRet38(
    json['ret'] as int,
  );
}

Map<String, dynamic> _$FRet38ToJson(FRet38 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FRet39 _$FRet39FromJson(Map<String, dynamic> json) {
  return FRet39(
    json['ret'] as int,
  );
}

Map<String, dynamic> _$FRet39ToJson(FRet39 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FRet40 _$FRet40FromJson(Map<String, dynamic> json) {
  return FRet40(
    json['ret'] as int,
  );
}

Map<String, dynamic> _$FRet40ToJson(FRet40 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FRet41 _$FRet41FromJson(Map<String, dynamic> json) {
  return FRet41(
    json['ret'] as bool,
  );
}

Map<String, dynamic> _$FRet41ToJson(FRet41 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FRet42 _$FRet42FromJson(Map<String, dynamic> json) {
  return FRet42(
    (json['ret'] as List)?.map((e) => e as bool)?.toList(),
  );
}

Map<String, dynamic> _$FRet42ToJson(FRet42 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FRet43 _$FRet43FromJson(Map<String, dynamic> json) {
  return FRet43(
    json['ret'] as int,
  );
}

Map<String, dynamic> _$FRet43ToJson(FRet43 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FRet44 _$FRet44FromJson(Map<String, dynamic> json) {
  return FRet44(
    (json['ret'] as List)?.map((e) => e as int)?.toList(),
  );
}

Map<String, dynamic> _$FRet44ToJson(FRet44 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FRet45 _$FRet45FromJson(Map<String, dynamic> json) {
  return FRet45(
    json['ret'] as int,
  );
}

Map<String, dynamic> _$FRet45ToJson(FRet45 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FRet46 _$FRet46FromJson(Map<String, dynamic> json) {
  return FRet46(
    (json['ret'] as List)?.map((e) => e as int)?.toList(),
  );
}

Map<String, dynamic> _$FRet46ToJson(FRet46 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FRet47 _$FRet47FromJson(Map<String, dynamic> json) {
  return FRet47(
    json['ret'] as int,
  );
}

Map<String, dynamic> _$FRet47ToJson(FRet47 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FRet48 _$FRet48FromJson(Map<String, dynamic> json) {
  return FRet48(
    (json['ret'] as List)?.map((e) => e as int)?.toList(),
  );
}

Map<String, dynamic> _$FRet48ToJson(FRet48 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FRet49 _$FRet49FromJson(Map<String, dynamic> json) {
  return FRet49(
    json['ret'] as int,
  );
}

Map<String, dynamic> _$FRet49ToJson(FRet49 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FRet50 _$FRet50FromJson(Map<String, dynamic> json) {
  return FRet50(
    (json['ret'] as List)?.map((e) => e as int)?.toList(),
  );
}

Map<String, dynamic> _$FRet50ToJson(FRet50 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FRet51 _$FRet51FromJson(Map<String, dynamic> json) {
  return FRet51(
    (json['ret'] as List)?.map((e) => e as String)?.toList(),
  );
}

Map<String, dynamic> _$FRet51ToJson(FRet51 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FRet52 _$FRet52FromJson(Map<String, dynamic> json) {
  return FRet52(
    (json['ret'] as List)?.map((e) => e as String)?.toList(),
  );
}

Map<String, dynamic> _$FRet52ToJson(FRet52 instance) => <String, dynamic>{
      'ret': instance.ret,
    };

FParam53 _$FParam53FromJson(Map<String, dynamic> json) {
  return FParam53(
    json['p0'] as String,
    json['p1'] as int,
    _$enumDecodeNullable(_$GenderEnumMap, json['p2']),
    json['p3'] == null
        ? null
        : Conversation.fromJson(json['p3'] as Map<String, dynamic>),
  );
}

Map<String, dynamic> _$FParam53ToJson(FParam53 instance) => <String, dynamic>{
      'p0': instance.p0,
      'p1': instance.p1,
      'p2': _$GenderEnumMap[instance.p2],
      'p3': instance.p3,
    };

const _$GenderEnumMap = {
  Gender.FEMALE: 'FEMALE',
  Gender.MALE: 'MALE',
};


<|start_filename|>fidl/example/android/fidlprocessor/src/test/java/com/infinateloop/fidl/CodeGenerateTest.java<|end_filename|>
package com.infinateloop.fidl;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;

import org.junit.Test;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

import javax.lang.model.element.Modifier;

public class CodeGenerateTest {
    private String packageName = "com.infinateloop.fidl";
    private String className = "IUserService";
    private ClassName interfaceClassName = ClassName.get(packageName, className);

    @Test
    public void superclass() throws Exception {
        TypeSpec channelClass = TypeSpec.classBuilder(interfaceClassName.simpleName() + "Stub")
                .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
                .superclass(ClassName.bestGuess("com.infiniteloop.fidl.Binder"))
                .build();

        JavaFile javaFile = JavaFile.builder(packageName, channelClass).build();
        javaFile.writeTo(System.out);
    }

    @Test
    public void addSuperinterface() throws Exception {
        TypeSpec channelClass = TypeSpec.classBuilder(interfaceClassName.simpleName() + "Stub")
                .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
                .superclass(ClassName.bestGuess("com.infiniteloop.fidl.Binder"))
                .addSuperinterface(Class.forName(interfaceClassName.canonicalName()))
                .build();

        JavaFile javaFile = JavaFile.builder(packageName, channelClass).build();
        javaFile.writeTo(System.out);
    }

    @Test
    public void addField() throws Exception {
        TypeSpec channelClass = TypeSpec.classBuilder(interfaceClassName.simpleName() + "Stub")
                .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
                .superclass(ClassName.bestGuess("com.infiniteloop.fidl.Binder"))
                .addSuperinterface(Class.forName(interfaceClassName.canonicalName()))
                .addField(FieldSpec.builder(String.class, "CHANNEL_NAME", Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
                        .initializer(interfaceClassName.simpleName()).build())
                .build();
        JavaFile javaFile = JavaFile.builder(packageName, channelClass).build();
        javaFile.writeTo(System.out);
    }

    @Test
    public void addMethod() throws Exception {
        ClassName interfaceClassName = ClassName.get(packageName, className);
        TypeSpec channelClass = TypeSpec.classBuilder(interfaceClassName.simpleName() + "Stub")
                .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
                .superclass(ClassName.bestGuess("com.infiniteloop.fidl.Binder"))
                .addSuperinterface(Class.forName(interfaceClassName.canonicalName()))

                .addField(FieldSpec.builder(String.class, "CHANNEL_NAME", Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
                        .initializer(interfaceClassName.simpleName()).build())

                .addMethod(MethodSpec.methodBuilder("getChannelName")
                        .addAnnotation(Override.class)
                        .addModifiers(Modifier.PUBLIC).returns(String.class)
                        .addStatement("return CHANNEL_NAME").build())

                .addMethod(MethodSpec.methodBuilder("onMethodCall")
                        .addAnnotation(Override.class)
                        .addModifiers(Modifier.PUBLIC)
                        .addParameter(Class.forName("com.infinateloop.fidl.MethodCall"), "call")
                        .addParameter(Class.forName("com.infinateloop.fidl.MethodChannel$Result"), "result")
                        .returns(TypeName.VOID)
                        .addStatement("").build())
                .build();
        JavaFile javaFile = JavaFile.builder(packageName, channelClass).build();
        javaFile.writeTo(System.out);
    }

    @Test
    public void addInnerMethodParams() throws Exception {
        ClassName interfaceClassName = ClassName.get(packageName, className);
        TypeSpec channelClass = TypeSpec.classBuilder(interfaceClassName.simpleName() + "Stub")
                .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
                .superclass(ClassName.bestGuess("com.infiniteloop.fidl.Binder"))
                .addSuperinterface(Class.forName(interfaceClassName.canonicalName()))

                .addField(FieldSpec.builder(String.class, "CHANNEL_NAME", Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
                        .initializer(interfaceClassName.simpleName()).build())

                .addMethod(MethodSpec.methodBuilder("getChannelName")
                        .addAnnotation(Override.class)
                        .addModifiers(Modifier.PUBLIC).returns(String.class)
                        .addStatement("return CHANNEL_NAME").build())

                .addMethod(MethodSpec.methodBuilder("onMethodCall")
                        .addAnnotation(Override.class)
                        .addModifiers(Modifier.PUBLIC)
                        .addParameter(Class.forName("com.infinateloop.fidl.MethodCall"), "call")
                        .addParameter(Class.forName("com.infinateloop.fidl.FlutterPlugin$Result"), "result")
                        .returns(TypeName.VOID)
                        .addStatement("").build())
                .build();
        JavaFile javaFile = JavaFile.builder(packageName, channelClass).build();
        javaFile.writeTo(System.out);
    }

    @Test
    public void generateCodeBlock() throws Exception {
        ClassName interfaceClassName = ClassName.get(packageName, className);
        Class interfaceClass = Class.forName(interfaceClassName.canonicalName());
        Method[] methods = interfaceClass.getMethods();
        CodeBlock.Builder blockBuilder = CodeBlock.builder();
        if (methods.length > 0) {
            generateCode(methods, blockBuilder);
        }

        TypeSpec channelClass = TypeSpec.classBuilder(interfaceClassName.simpleName() + "Stub")
                .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
                .superclass(ClassName.bestGuess("com.infiniteloop.fidl.Binder"))
                .addSuperinterface(Class.forName(interfaceClassName.canonicalName()))

                .addField(FieldSpec.builder(String.class, "CHANNEL_NAME", Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
                        .initializer("\"$L\"", interfaceClassName.canonicalName()).build())

                .addMethod(MethodSpec.methodBuilder("getChannelName")
                        .addAnnotation(Override.class)
                        .addModifiers(Modifier.PUBLIC).returns(String.class)
                        .addStatement("return CHANNEL_NAME").build())

                .addMethod(MethodSpec.methodBuilder("onMethodCall")
                        .addAnnotation(Override.class)
                        .addModifiers(Modifier.PUBLIC)
                        .addParameter(Class.forName("com.infinateloop.fidl.MethodCall"), "call")
                        .addParameter(Class.forName("com.infinateloop.fidl.FlutterPlugin$Result"), "result")
                        .returns(TypeName.VOID)
                        .addCode(blockBuilder.build()).build())
                .build();
        JavaFile javaFile = JavaFile.builder(packageName, channelClass).build();
        javaFile.writeTo(System.out);
    }

    private boolean isBasicType(Type type) {
        return type.equals(void.class) || type.equals(Void.TYPE) ||
                type.equals(boolean.class) || type.equals(Boolean.TYPE) ||
                type.equals(byte.class) || type.equals(Byte.TYPE) ||
                type.equals(short.class) || type.equals(Short.TYPE) ||
                type.equals(int.class) || type.equals(Integer.TYPE) ||
                type.equals(long.class) || type.equals(Long.TYPE) ||
                type.equals(float.class) || type.equals(Float.TYPE) ||
                type.equals(double.class) || type.equals(Double.TYPE) ||
                type.equals(String.class) ||
                type.equals(byte[].class) || type.equals(Byte[].class) ||
                type.equals(int[].class) || type.equals(Integer[].class) ||
                type.equals(long[].class) || type.equals(Long[].class) ||
                type.equals(double[].class) || type.equals(Double[].class) ||
                type.equals(List.class) ||
                type.equals(Map.class);
    }

    private void generateCode(Method[] methods, CodeBlock.Builder builder) {
        for (Method method : methods) {

            ClassName jsonIteratorClazz = ClassName.get("com.jsoniter", "JsonIterator");
            ClassName typeLiteralClazz = ClassName.get("com.jsoniter.spi", "TypeLiteral");

            builder.beginControlFlow("if(call.method.equals(\"$L\"))", method.getName());
            Type[] parameterTypes = method.getGenericParameterTypes();
            Type returnType = method.getGenericReturnType();
            if (parameterTypes.length > 0) {
                for (int i = 0; i < parameterTypes.length; i++) {
                    // 参数类型判断
                    if (isBasicType(parameterTypes[i])) {
                        builder.addStatement("$T p$L = call.argument(\"$L\")", parameterTypes[i], i, i);
                    } else {
                        builder.addStatement("$T json$L = call.argument(\"$L\")", String.class, i, i);
                        builder.addStatement("$T p$L = $T.deserialize(json$L, new $T<$T>(){})", parameterTypes[i], i, jsonIteratorClazz, i, typeLiteralClazz, parameterTypes[i]);
                    }
                }
            }

            if (returnType.equals(Void.TYPE)) {
                builder.add("$L(", method.getName());
            } else {
                builder.add("$T ret = $L(", returnType, method.getName());
            }
            for (int i = 0; i < parameterTypes.length; i++) {
                if (i == parameterTypes.length - 1) {
                    builder.add("p$L", i);
                } else {
                    builder.add("p$L,", i);
                }
            }
            builder.add(");\n");

            if (returnType.equals(Void.TYPE)) {
                builder.addStatement("result.success(null)");
            } else {
                builder.addStatement("result.success(ret)");
            }
            builder.addStatement("return");

            builder.endControlFlow();
        }
    }

    @Test
    public void getInterfaceMethods() throws Exception {
        Class clazz = Class.forName("com.infinateloop.fidl.IUserService");
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println(method.getName() + ":");
            System.out.println("params:");
            Type[] types = method.getGenericParameterTypes();
            if (types.length > 0) {
                for (int i = 0; i < types.length; i++) {
                    System.out.println(i + ":" + types[i]);
                }
            } else {
                System.out.println("void");
            }
//            System.out.println("signature:"+method.get);
            Type returnType = method.getGenericReturnType();
            System.out.println("return:" + returnType.toString());
            System.out.println(returnType.equals(void.class));
        }
    }
}


<|start_filename|>fidl/android/src/main/java/com/infiniteloop/fidl/MultiMessageCodec.java<|end_filename|>
package com.infiniteloop.fidl;

import android.util.Log;

import com.jsoniter.output.JsonStream;

import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import io.flutter.BuildConfig;
import io.flutter.plugin.common.MessageCodec;

/**
 * MessageCodec using the Flutter standard binary encoding.
 *
 * <p>This codec is guaranteed to be compatible with the corresponding
 * <a href="https://docs.flutter.io/flutter/services/StandardMessageCodec-class.html">StandardMessageCodec</a>
 * on the Dart side. These parts of the Flutter SDK are evolved synchronously.</p>
 *
 * <p>Supported messages are acyclic values of these forms:</p>
 *
 * <ul>
 * <li>null</li>
 * <li>Booleans</li>
 * <li>Bytes, Shorts, Integers, Longs</li>
 * <li>BigIntegers (see below)</li>
 * <li>Floats, Doubles</li>
 * <li>Strings</li>
 * <li>byte[], int[], long[], double[]</li>
 * <li>Lists of supported values</li>
 * <li>Maps with supported keys and values</li>
 * </ul>
 *
 * <p>On the Dart side, these values are represented as follows:</p>
 *
 * <ul>
 * <li>null: null</li>
 * <li>Boolean: bool</li>
 * <li>Byte, Short, Integer, Long: int</li>
 * <li>Float, Double: double</li>
 * <li>String: String</li>
 * <li>byte[]: Uint8List</li>
 * <li>int[]: Int32List</li>
 * <li>long[]: Int64List</li>
 * <li>double[]: Float64List</li>
 * <li>List: List</li>
 * <li>Map: Map</li>
 * </ul>
 *
 * <p>BigIntegers are represented in Dart as strings with the
 * hexadecimal representation of the integer's value.</p>
 *
 * <p>To extend the codec, overwrite the writeValue and readValueOfType methods.</p>
 */
public class MultiMessageCodec implements MessageCodec<Object> {
    private static final String TAG = "MultiMessageCodec#";
    public static final MultiMessageCodec INSTANCE = new MultiMessageCodec();

    @Override
    public ByteBuffer encodeMessage(Object message) {
        if (message == null) {
            return null;
        }
        final ExposedByteArrayOutputStream stream = new ExposedByteArrayOutputStream();
        writeValue(stream, message);
        final ByteBuffer buffer = ByteBuffer.allocateDirect(stream.size());
        buffer.put(stream.buffer(), 0, stream.size());
        return buffer;
    }

    @Override
    public Object decodeMessage(ByteBuffer message) {
        if (message == null) {
            return null;
        }
        message.order(ByteOrder.nativeOrder());
        final Object value = readValue(message);
        if (message.hasRemaining()) {
            throw new IllegalArgumentException("Message corrupted");
        }
        return value;
    }

    private static final boolean LITTLE_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN;
    private static final Charset UTF8 = Charset.forName("UTF8");
    private static final byte NULL = 0;
    private static final byte TRUE = 1;
    private static final byte FALSE = 2;
    private static final byte INT = 3;
    private static final byte LONG = 4;
    private static final byte BIGINT = 5;
    private static final byte DOUBLE = 6;
    private static final byte STRING = 7;
    private static final byte BYTE_ARRAY = 8;
    private static final byte INT_ARRAY = 9;
    private static final byte LONG_ARRAY = 10;
    private static final byte DOUBLE_ARRAY = 11;
    private static final byte LIST = 12;
    private static final byte MAP = 13;

    /**
     * Writes an int representing a size to the specified stream.
     * Uses an expanding code of 1 to 5 bytes to optimize for small values.
     */
    protected static final void writeSize(ByteArrayOutputStream stream, int value) {
        if (BuildConfig.DEBUG && 0 > value) {
            Log.e(TAG, "Attempted to write a negative size.");
        }
        if (value < 254) {
            stream.write(value);
        } else if (value <= 0xffff) {
            stream.write(254);
            writeChar(stream, value);
        } else {
            stream.write(255);
            writeInt(stream, value);
        }
    }

    /**
     * Writes the least significant two bytes of the specified int to the
     * specified stream.
     */
    protected static final void writeChar(ByteArrayOutputStream stream, int value) {
        if (LITTLE_ENDIAN) {
            stream.write(value);
            stream.write(value >>> 8);
        } else {
            stream.write(value >>> 8);
            stream.write(value);
        }
    }

    /**
     * Writes the specified int as 4 bytes to the specified stream.
     */
    protected static final void writeInt(ByteArrayOutputStream stream, int value) {
        if (LITTLE_ENDIAN) {
            stream.write(value);
            stream.write(value >>> 8);
            stream.write(value >>> 16);
            stream.write(value >>> 24);
        } else {
            stream.write(value >>> 24);
            stream.write(value >>> 16);
            stream.write(value >>> 8);
            stream.write(value);
        }
    }

    /**
     * Writes the specified long as 8 bytes to the specified stream.
     */
    protected static final void writeLong(ByteArrayOutputStream stream, long value) {
        if (LITTLE_ENDIAN) {
            stream.write((byte) value);
            stream.write((byte) (value >>> 8));
            stream.write((byte) (value >>> 16));
            stream.write((byte) (value >>> 24));
            stream.write((byte) (value >>> 32));
            stream.write((byte) (value >>> 40));
            stream.write((byte) (value >>> 48));
            stream.write((byte) (value >>> 56));
        } else {
            stream.write((byte) (value >>> 56));
            stream.write((byte) (value >>> 48));
            stream.write((byte) (value >>> 40));
            stream.write((byte) (value >>> 32));
            stream.write((byte) (value >>> 24));
            stream.write((byte) (value >>> 16));
            stream.write((byte) (value >>> 8));
            stream.write((byte) value);
        }
    }

    /**
     * Writes the specified double as 8 bytes to the specified stream.
     */
    protected static final void writeDouble(ByteArrayOutputStream stream, double value) {
        writeLong(stream, Double.doubleToLongBits(value));
    }

    /**
     * Writes the length and then the actual bytes of the specified array to
     * the specified stream.
     */
    protected static final void writeBytes(ByteArrayOutputStream stream, byte[] bytes) {
        writeSize(stream, bytes.length);
        stream.write(bytes, 0, bytes.length);
    }

    /**
     * Writes a number of padding bytes to the specified stream to ensure that
     * the next value is aligned to a whole multiple of the specified alignment.
     * An example usage with alignment = 8 is to ensure doubles are word-aligned
     * in the stream.
     */
    protected static final void writeAlignment(ByteArrayOutputStream stream, int alignment) {
        final int mod = stream.size() % alignment;
        if (mod != 0) {
            for (int i = 0; i < alignment - mod; i++) {
                stream.write(0);
            }
        }
    }

    /**
     * Writes a type discriminator byte and then a byte serialization of the
     * specified value to the specified stream.
     *
     * <p>Subclasses can extend the codec by overriding this method, calling
     * super for values that the extension does not handle.</p>
     */
    protected void writeValue(ByteArrayOutputStream stream, Object value) {
        if (value == null) {
            stream.write(NULL);
        } else if (value == Boolean.TRUE) {
            stream.write(TRUE);
        } else if (value == Boolean.FALSE) {
            stream.write(FALSE);
        } else if (value instanceof Number) {
            if (value instanceof Integer || value instanceof Short || value instanceof Byte) {
                stream.write(INT);
                writeInt(stream, ((Number) value).intValue());
            } else if (value instanceof Long) {
                stream.write(LONG);
                writeLong(stream, (long) value);
            } else if (value instanceof Float || value instanceof Double) {
                stream.write(DOUBLE);
                writeAlignment(stream, 8);
                writeDouble(stream, ((Number) value).doubleValue());
            } else if (value instanceof BigInteger) {
                stream.write(BIGINT);
                writeBytes(stream,
                        ((BigInteger) value).toString(16).getBytes(UTF8));
            } else {
                throw new IllegalArgumentException("Unsupported Number type: " + value.getClass());
            }
        } else if (value instanceof String) {
            stream.write(STRING);
            writeBytes(stream, ((String) value).getBytes(UTF8));
        } else if (value instanceof byte[]) {
            stream.write(BYTE_ARRAY);
            writeBytes(stream, (byte[]) value);
        } else if (value instanceof int[]) {
            stream.write(INT_ARRAY);
            final int[] array = (int[]) value;
            writeSize(stream, array.length);
            writeAlignment(stream, 4);
            for (final int n : array) {
                writeInt(stream, n);
            }
        } else if (value instanceof long[]) {
            stream.write(LONG_ARRAY);
            final long[] array = (long[]) value;
            writeSize(stream, array.length);
            writeAlignment(stream, 8);
            for (final long n : array) {
                writeLong(stream, n);
            }
        } else if (value instanceof double[]) {
            stream.write(DOUBLE_ARRAY);
            final double[] array = (double[]) value;
            writeSize(stream, array.length);
            writeAlignment(stream, 8);
            for (final double d : array) {
                writeDouble(stream, d);
            }
        } else if (value instanceof List) {
            stream.write(LIST);
            final List<?> list = (List) value;
            writeSize(stream, list.size());
            for (final Object o : list) {
                writeValue(stream, o);
            }
        } else if (value instanceof Map) {
            stream.write(MAP);
            final Map<?, ?> map = (Map) value;
            writeSize(stream, map.size());
            for (final Entry<?, ?> entry : map.entrySet()) {
                writeValue(stream, entry.getKey());
                writeValue(stream, entry.getValue());
            }
        } else {
            throw new IllegalArgumentException("Unsupported value: " + value);
        }
    }

    /**
     * Reads an int representing a size as written by writeSize.
     */
    protected static final int readSize(ByteBuffer buffer) {
        if (!buffer.hasRemaining()) {
            throw new IllegalArgumentException("Message corrupted");
        }
        final int value = buffer.get() & 0xff;
        if (value < 254) {
            return value;
        } else if (value == 254) {
            return buffer.getChar();
        } else {
            return buffer.getInt();
        }
    }

    /**
     * Reads a byte array as written by writeBytes.
     */
    protected static final byte[] readBytes(ByteBuffer buffer) {
        final int length = readSize(buffer);
        final byte[] bytes = new byte[length];
        buffer.get(bytes);
        return bytes;
    }

    /**
     * Reads alignment padding bytes as written by writeAlignment.
     */
    protected static final void readAlignment(ByteBuffer buffer, int alignment) {
        final int mod = buffer.position() % alignment;
        if (mod != 0) {
            buffer.position(buffer.position() + alignment - mod);
        }
    }

    /**
     * Reads a value as written by writeValue.
     */
    protected final Object readValue(ByteBuffer buffer) {
        if (!buffer.hasRemaining()) {
            throw new IllegalArgumentException("Message corrupted");
        }
        final byte type = buffer.get();
        return readValueOfType(type, buffer);
    }

    /**
     * Reads a value of the specified type.
     *
     * <p>Subclasses may extend the codec by overriding this method, calling
     * super for types that the extension does not handle.</p>
     */
    protected Object readValueOfType(byte type, ByteBuffer buffer) {
        final Object result;
        switch (type) {
            case NULL:
                result = null;
                break;
            case TRUE:
                result = true;
                break;
            case FALSE:
                result = false;
                break;
            case INT:
                result = buffer.getInt();
                break;
            case LONG:
                result = buffer.getLong();
                break;
            case BIGINT: {
                final byte[] hex = readBytes(buffer);
                result = new BigInteger(new String(hex, UTF8), 16);
                break;
            }
            case DOUBLE:
                readAlignment(buffer, 8);
                result = buffer.getDouble();
                break;
            case STRING: {
                final byte[] bytes = readBytes(buffer);
                result = new String(bytes, UTF8);
                break;
            }
            case BYTE_ARRAY: {
                result = readBytes(buffer);
                break;
            }
            case INT_ARRAY: {
                final int length = readSize(buffer);
                final int[] array = new int[length];
                readAlignment(buffer, 4);
                buffer.asIntBuffer().get(array);
                result = array;
                buffer.position(buffer.position() + 4 * length);
                break;
            }
            case LONG_ARRAY: {
                final int length = readSize(buffer);
                final long[] array = new long[length];
                readAlignment(buffer, 8);
                buffer.asLongBuffer().get(array);
                result = array;
                buffer.position(buffer.position() + 8 * length);
                break;
            }
            case DOUBLE_ARRAY: {
                final int length = readSize(buffer);
                final double[] array = new double[length];
                readAlignment(buffer, 8);
                buffer.asDoubleBuffer().get(array);
                result = array;
                buffer.position(buffer.position() + 8 * length);
                break;
            }
            case LIST: {
                final int size = readSize(buffer);
                final List<Object> list = new ArrayList<>(size);
                for (int i = 0; i < size; i++) {
                    list.add(readValue(buffer));
                }
                result = list;
                break;
            }
            case MAP: {
                final int size = readSize(buffer);
                final Map<Object, Object> map = new HashMap<>();
                for (int i = 0; i < size; i++) {
                    map.put(readValue(buffer), readValue(buffer));
                }
                result = map;
                break;
            }
            default:
                throw new IllegalArgumentException("Message corrupted");
        }
        return result;
    }
}


<|start_filename|>fidl/example/lib/main.dart<|end_filename|>
import 'package:fidl_example/fidl/com.infiniteloop.fidl_example.bean/AUser.dart';
import 'package:fidl_example/fidl/com.infiniteloop.fidl_example.bean/User.dart';
import 'package:fidl_example/fidl/com.infiniteloop.fidl_example.bean/UserInfo.dart';
import 'package:fidl_example/fidl/com.infiniteloop.fidl_example/IChatService.dart';
import 'package:fidl_example/fidl/com.infiniteloop.fidl_example/IUserService.dart';
import 'package:fidl_example/shape_button.dart';
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:fidl/fidl.dart';

import 'chat_screen.dart';
import 'fidl/com.infiniteloop.fidl_example.bean/MessageStatus.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _platformVersion = 'Unknown';
  ChannelConnection _channelConnection;
  ChannelConnection _chatConnection;

  @override
  void initState() {
    super.initState();
    _channelConnection = ChannelConnection(() {
      print('onConnected');
    }, () {
      print('onDisconnected');
    });
    _chatConnection = ChannelConnection(() {
      print('chatService onConnected');
    }, () {
      print('chatService onDisconnected');
    });
    initPlatformState();
  }

  @override
  void dispose() {
    super.dispose();
    Fidl.unbindChannel(IChatService.CHANNEL_NAME, _channelConnection);
  }

  Future<void> initPlatformState() async {
    String platformVersion;
    try {
      platformVersion = await Fidl.platformVersion;
    } on PlatformException {
      platformVersion = 'Failed to get platform version.';
    }

    if (!mounted) return;

    setState(() {
      _platformVersion = platformVersion;
    });

    bool success =
        await Fidl.bindChannel(IUserService.CHANNEL_NAME, _channelConnection);
    if (!success) {
      return;
    }

    String ret = await IUserService.initEnum1(MessageStatus.Readed);
    print('init result is $ret');

    Set<String> set = Set();
    set.add("value0");
    set.add("value1");
    set.add("value2");
    await IUserService.initList0(set.toList());
    await IUserService.initSet2(set);

    UserInfo info = UserInfo();
    info.age = 16;
    await IUserService.initObj0(info);

    AUser aUser = AUser();
    aUser.country = 'China';
    aUser.age = 16;
    await IUserService.initObj2(aUser);

    User<String> user = User();
    user.age = 16;
    await IUserService.initObj3(user);

    await Fidl.unbindChannel(IUserService.CHANNEL_NAME, _channelConnection);

    await Fidl.bindChannel(IChatService.CHANNEL_NAME, _chatConnection);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(primarySwatch: Colors.amber),
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Builder(
          builder: (context) => Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text('Running on: $_platformVersion\n'),
                ShapeButton(
                    onPressed: () async {
                      if (_chatConnection.connected) {
                        User<String> mySelf = User();
                        mySelf.age = 16;
                        mySelf.country = 'China';
                        mySelf.name = 'Oscar';
                        mySelf.uid = '1';
                        await IChatService.init(mySelf);
                        Navigator.push(
                            context,
                            MaterialPageRoute(
                                builder: (context) => ChatScreen()));
                      } else {
                        var dialog = AlertDialog(
                            title: Text('Warning!'),
                            content: Text('Chat service is not connected!'),
                            actions: <Widget>[
                              FlatButton(
                                  child: const Text('OK'),
                                  onPressed: () {
                                    Navigator.of(context).pop(true);
                                  })
                            ]);
                        showDialog<bool>(
                            context: context, builder: (_) => dialog);
                      }
                    },
                    child:
                        Text("Start chatting", style: TextStyle(fontSize: 18))),
              ],
            ),
          ),
        ),
      ),
    );
  }
}


<|start_filename|>fidl/example/fidl/com.infiniteloop.fidl_example.bean.Gender.json<|end_filename|>
{"type":"com.infiniteloop.fidl_example.bean.Gender(FEMALE,MALE)","kind":"enum","fields":[],"superType":""}

<|start_filename|>fidl/example/fidl/com.infiniteloop.fidl_example.IChatService.fidl.json<|end_filename|>
{"cls":"com.infiniteloop.fidl_example.IChatService","kind":"fidl","methods":[{"name":"init","returns":"bool","parameters":[{"name":"user","type":"com.infiniteloop.fidl_example.bean.User(String)"}]}]}

<|start_filename|>fidl/example/android/app/src/main/java/com/infiniteloop/fidl_example/IChatService.java<|end_filename|>
package com.infiniteloop.fidl_example;

import com.infinateloop.fidl.annotation.FIDL;
import com.infiniteloop.fidl_example.bean.User;

@FIDL
public interface IChatService {
    public boolean init(User<String> user);
}


<|start_filename|>fidl/example/lib/fidl/com.infiniteloop.fidl_example/IChatService.dart<|end_filename|>
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:fidl/fidl.dart';
import "../com.infiniteloop.fidl_example.bean/User.dart";

part 'IChatService.g.dart';

class IChatService {
  static const String CHANNEL_NAME = 'com.infiniteloop.fidl_example.IChatService';
  static const MethodChannel _channel =
      const MethodChannel(CHANNEL_NAME, const MultiMethodCodec());

  static Future<bool> init(User<String> user) async {
    var p0 = FParam0(user).toJson()['p0'];
    var param = Fidl.objectCodec.encode([p0]);
    var ret = await _channel.invokeMethod('init', param);
    var json = Fidl.objectCodec.decode(ret[0]);
    return FRet0.fromJson(json).ret;
  }

}

@JsonSerializable()
class FRet0 {
  FRet0(this.ret);

  bool ret;

  factory FRet0.fromJson(Map<String, dynamic> json) => _$FRet0FromJson(json);

  Map<String, dynamic> toJson() => _$FRet0ToJson(this);
}
@JsonSerializable()
class FParam0 {
  FParam0(this.p0);

  User<String> p0;

  factory FParam0.fromJson(Map<String, dynamic> json) => _$FParam0FromJson(json);

  Map<String, dynamic> toJson() => _$FParam0ToJson(this);
}



<|start_filename|>fidl/android/src/main/java/com/infiniteloop/fidl/Channel.java<|end_filename|>
package com.infiniteloop.fidl;

import android.support.annotation.NonNull;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;

public abstract class Channel implements FlutterPlugin, MethodChannel.MethodCallHandler, IChannel {
    private MethodChannel channel;

    @Override
    public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
    }

    public abstract String getChannelName();

    @Override
    public void onDetachedFromEngine(FlutterPluginBinding binding) {
    }

    public void attachMethodChannel(BinaryMessenger messenger) {
        if (channel == null) {
            channel = new MethodChannel(messenger, getChannelName(), MultiMethodCodec.INSTANCE);
        }
        channel.setMethodCallHandler(this);
    }

    void detachMethodChannel() {
        channel.setMethodCallHandler(null);
    }

    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
        Object obj = onMethodCall(call.method, (List<byte[]>) call.arguments);
        Map<String, Object> map = new HashMap<>();
        map.put("ret", obj);
        result.success(FidlChannel.objectCodec.encode(map));
    }

    public abstract Object onMethodCall(String method, List<byte[]> arguments);
}


<|start_filename|>fidl_model/fidl/com.infiniteloop.fidl.bean.MessageStatus.json<|end_filename|>
{
  "type": "com.infiniteloop.fidl.bean.MessageStatus(Played,Readed,Unread,AllMentioned,Mentioned,Send_Failure,Sent,Sending)",
  "kind": "enum",
  "fields": [
    {
      "name": "value",
      "type": "int"
    }
  ],
  "superType": ""
}

<|start_filename|>fidl/example/android/app/src/main/java/com/infiniteloop/fidl_example/App.java<|end_filename|>
package com.infiniteloop.fidl_example;

import com.infiniteloop.fidl.FidlChannel;
import com.infiniteloop.fidl.JsonObjectCodec;

import io.flutter.app.FlutterApplication;

public class App extends FlutterApplication {
    @Override
    public void onCreate() {
        super.onCreate();
        FidlChannel.registerObjectCodec(new JsonObjectCodec());
    }
}
