简体   繁体   English

将IKVMC生成的对象序列化为JSON

[英]Serializing a IKVMC generated object to JSON

I have a java library that contains all the domain models for our backend REST API. 我有一个Java库,其中包含后端REST API的所有域模型。 The backend API is implemented in Java and translate Java objects to JSON using Jackson. 后端API用Java实现,并使用Jackson将Java对象转换为JSON。

Recently we need to implement a new feature and have a Windows .NET application talk to our API. 最近,我们需要实现一项新功能,并使Windows .NET应用程序与我们的API对话。 However, since the domain model (contract) is all in Java, we had to translate all the Java classes to C# classes so that we can use Json.NET to serialize/deserialize JSON, but this quickly became time-consuming. 但是,由于域模型(合同)全部使用Java,因此我们必须将所有Java类转换为C#类,以便我们可以使用Json.NET序列化/反序列化JSON,但这很快变得很耗时。 In addition, whenver there is contract change in Java we likely have to do this for C# classes also. 另外,只要Java中的合同发生变化,我们可能也必须对C#类执行此操作。

I searched online and found out IKVMC can translate a jar to a DLL, so I tried it out, however, it's causing some Json.NET serialization problems. 我在网上搜索,发现IKVMC可以将jar转换为DLL,因此我尝试了一下,但是,这导致了一些Json.NET序列化问题。

For example 例如

I have a Java object that looks like this: 我有一个看起来像这样的Java对象:

public class ApiToken {

    private String apiKey;

    private String apiSecret;

    public String getApiKey() {
        return apiKey;
    }

    public void setApiKey(String apiKey) {
        this.apiKey = apiKey;
    }

    public String getApiSecret() {
        return apiSecret;
    }

    public void setApiSecret(String apiSecret) {
        this.apiSecret = apiSecret;
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(apiKey, apiSecret);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        ApiToken other = (ApiToken) obj;
        return Objects.equal(this.apiKey, other.apiKey) && Objects.equal(this.apiSecret, other.apiSecret);
    }

    @Override
    public String toString() {
        return Objects.toStringHelper(this).add("apiKey", apiKey).add("apiSecret", apiSecret).toString();
    }
}

AFTER translation by ikvmc , it looks like this: 在ikvmc翻译之后 ,它看起来像这样:

public class ApiToken : Object
  {
    [LineNumberTable(11)]
    [MethodImpl(MethodImplOptions.NoInlining)]
    public ApiToken();
    public virtual string getApiKey();
    public virtual void setApiKey(string apiKey);
    public virtual string getApiSecret();
    public virtual void setApiSecret(string apiSecret);
    [LineNumberTable(35)]
    public override int hashCode();
    [LineNumberTable(new byte[] {159, 182, 100, 98, 99, 98, 110, 98, 103})]
    [MethodImpl(MethodImplOptions.NoInlining)]
    public override bool equals(object obj);
    [LineNumberTable(52)]
    public override string toString();
  }

when I create this object in C#, JSON.net does NOT seralize this object correctly. 当我在C#中创建此对象时,JSON.net 不能正确地序列化此对象。 Instead, it just produces an empty JSON {} 相反,它只会产生一个空的JSON {}

I suspect this is because there are no fields/properties exposed in the object that is generated by ikvmc. 我怀疑这是因为ikvmc生成的对象中没有公开的字段/属性。

Does anyone know if there's a workaround for this? 有人知道这是否有解决方法吗?

Thanks a lot and much appreciated 非常感谢,非常感谢

Update: This is how I'm serializing the object 更新:这就是我序列化对象的方式

  ApiToken apiToken = new ApiToken();
  apiToken.setApiKey("test");
  apiToken.setApiSecret("secret");
  string json = JsonConvert.SerializeObject(apiToken);

The json output is {}. json输出为{}。

I suspect this is because there are no fields/properties exposed in the object that is generated by ikvmc 我怀疑这是因为ikvmc生成的对象中没有公开的字段/属性

Yes. 是。

Does anyone know if there's a workaround for this? 有人知道这是否有解决方法吗?

You can do it by writing a custom ContractResolver and ValueProvider as below 您可以通过编写如下的自定义ContractResolverValueProvider来做到这一点

var obj = new ApiToken();
obj.setApiKey("X-X-X");
obj.setI(666);

var settings = new Newtonsoft.Json.JsonSerializerSettings() { 
                     ContractResolver = new MyContractResolver() 
               };

var json = JsonConvert.SerializeObject(obj, settings);
//json : {"ApiKey":"X-X-X","I":666}
var newobj = JsonConvert.DeserializeObject<ApiToken>(json, settings);

//Test class
public class ApiToken 
{
    private String apiKey;

    public String getApiKey()
    {
        return apiKey;
    }

    public void setApiKey(String apiKey)
    {
        this.apiKey = apiKey;
    }


    private int i;

    public int getI()
    {
        return i;
    }

    public void setI(int i)
    {
        this.i = i;
    }

    public string dummy()
    {
        return "abcde";
    }
}

public class MyContractResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
{
    protected override IList<Newtonsoft.Json.Serialization.JsonProperty> CreateProperties(Type type, Newtonsoft.Json.MemberSerialization memberSerialization)
    {
        //Find methods.  setXXX getXXX
        var properties = type.GetMethods()
            .Where(m => m.Name.Length > 3)
            .GroupBy(m => m.Name.Substring(3))
            .Where(g => g.Count() == 2 && g.Any(x=>x.Name=="set" + g.Key) && g.Any(x=>x.Name=="get" + g.Key))
            .ToList();

        //Create a JsonProperty for each set/getXXX pair
        var ret = properties.Select(prop=>
                    {
                        var jProp = new Newtonsoft.Json.Serialization.JsonProperty();
                        jProp.PropertyName = prop.Key;
                        jProp.PropertyType = prop.First(m => m.Name.StartsWith("get")).ReturnType;
                        jProp.ValueProvider = new MyValueProvider(prop.ToList());
                        jProp.Readable = jProp.Writable = true;
                        return jProp;
                    })
                    .ToList();

        return ret;
    }
}

public class MyValueProvider : Newtonsoft.Json.Serialization.IValueProvider
{
    List<MethodInfo> _MethodInfos = null;
    public MyValueProvider(List<MethodInfo> methodInfos)
    {
        _MethodInfos = methodInfos;
    }
    public object GetValue(object target)
    {
        return _MethodInfos.First(m => m.Name.StartsWith("get")).Invoke(target, null);
    }

    public void SetValue(object target, object value)
    {
        _MethodInfos.First(m => m.Name.StartsWith("set")).Invoke(target, new object[] { value });
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM