Сериализация / Десеализация через protobuf-сеть между C# и Java

#java #c# #serialization #protocol-buffers #protobuf-net

Вопрос:

У меня есть 2 приложения, использующие protobuf между ними. Первый (C#) с использованием protobuf-сети с сериализуемыми настройками визуализации объектов:

 [ProtoContract]
public class VisualSettings
{
    [ProtoContract]
    public class BodyPartHolder
    {
        [ProtoMember(1)]
        public BodyPartType type;
        [ProtoMember(2)]
        public int id;

        public BodyPartHolder() { }
        public BodyPartHolder(BodyPartType type, int id)
        {
            this.type = type;
            this.id = id;
        }

        public BodyPartHolder Copy()
        {
            return new BodyPartHolder(type, id);
        }
    }

    public interface IPaintHolder
    {
        int id { get; set; }
    }

    public interface ICustomPaintHolder
    {
        HSBColor hsb { get; set; }
    }

    [ProtoContract]
    [ProtoInclude(100, typeof(BaseBodyPaintHolder)), ProtoInclude(200, typeof(BaseWheelPaintHolder)), ProtoInclude(300, typeof(BaseGlassPaintHolder))]
    [ProtoInclude(400, typeof(BaseSmokePaintHolder)), ProtoInclude(500, typeof(BaseSuspensionPaintHolder)), ProtoInclude(600, typeof(BaseInteriorPaintHolder))]
    public abstract class BasePaintHolder
    {
        [JsonIgnore]
        public bool isCustom => this is ICustomPaintHolder;
        [JsonIgnore]
        public string materialName => CarPaintMaterials.GetName(material);
        [JsonIgnore]
        public CarPaintType material => materials[materialId];

        [ProtoMember(1)]
        public int materialId;

        protected abstract CarPaintType[] materials { get; }

        public BasePaintHolder() { }
        public BasePaintHolder(int materialId)
        {
            this.materialId = materialId;
        }

        public virtual float GetCategoryCostCoefficient(CarSharedMeta carMeta)
        {
            return BasePaintItem.DefaultCostCoefficient;
        }

        public float GetMaterialCostCoefficient(CarSharedMeta carMeta)
        {
            return carMeta.GetPaintMaterialCostCoefficient(material);
        }

        public abstract bool Equals(BasePaintHolder other);
    }

    [ProtoContract]
    [ProtoInclude(100, typeof(BodyPaintHolder)), ProtoInclude(200, typeof(BodyCustomPaintHolder))]
    public abstract class BaseBodyPaintHolder : BasePaintHolder
    {
        [ProtoMember(1)]
        public BodyPartType part;

        protected override CarPaintType[] materials => CarPaintMaterials.Body;

        public BaseBodyPaintHolder() { }
        public BaseBodyPaintHolder(BodyPartType part, int materialId) : base(materialId)
        {
            this.part = part;
        }

        public override float GetCategoryCostCoefficient(CarSharedMeta carMeta)
        {
            return carMeta.GetPaintCategoryCostCoefficient(part);
        }

        public abstract BaseBodyPaintHolder Copy();
    }

    [ProtoContract]
    public class BodyPaintHolder : BaseBodyPaintHolder, IPaintHolder
    {
        [ProtoMember(1)]
        public int id { get; set; }

        public BodyPaintHolder() { }
        public BodyPaintHolder(BodyPartType part, int materialId, int id) : base(part, materialId)
        {
            this.id = id;
        }

        public override BaseBodyPaintHolder Copy()
        {
            return new BodyPaintHolder(part, materialId, id);
        }

        public override bool Equals(BasePaintHolder other)
        {
            var otherPaint = other as BodyPaintHolder;
            return (otherPaint != null) amp;amp; (otherPaint.part == part) amp;amp; (otherPaint.materialId == materialId) amp;amp; (otherPaint.id == id);
        }
    }

    [ProtoContract]
    public class BodyCustomPaintHolder : BaseBodyPaintHolder, ICustomPaintHolder
    {
        [ProtoMember(1)]
        public HSBColor hsb { get; set; }

        public BodyCustomPaintHolder() { }
        public BodyCustomPaintHolder(BodyPartType part, int materialId, HSBColor hsb) : base(part, materialId)
        {
            this.hsb = hsb;
        }

        public override BaseBodyPaintHolder Copy()
        {
            return new BodyCustomPaintHolder(part, materialId, hsb);
        }

        public override bool Equals(BasePaintHolder other)
        {
            var otherPaint = other as BodyCustomPaintHolder;
            return (otherPaint != null) amp;amp; (otherPaint.part == part) amp;amp; (otherPaint.materialId == materialId) amp;amp; HSBColor.EqualsOpaque(otherPaint.hsb, hsb);
        }
    }

    [ProtoContract]
    [ProtoInclude(100, typeof(WheelPaintHolder)), ProtoInclude(200, typeof(WheelCustomPaintHolder))]
    public abstract class BaseWheelPaintHolder : BasePaintHolder
    {
        [ProtoMember(1)]
        public WheelPaintPart part;

        protected override CarPaintType[] materials => CarPaintMaterials.Wheel;

        public BaseWheelPaintHolder() { }
        public BaseWheelPaintHolder(WheelPaintPart part, int materialId) : base(materialId)
        {
            this.part = part;
        }

        public abstract BaseWheelPaintHolder Copy();
    }

    [ProtoContract]
    public class WheelPaintHolder : BaseWheelPaintHolder, IPaintHolder
    {
        [ProtoMember(1)]
        public int id { get; set; }

        public WheelPaintHolder() { }
        public WheelPaintHolder(WheelPaintPart part, int materialId, int id) : base(part, materialId)
        {
            this.id = id;
        }

        public override BaseWheelPaintHolder Copy()
        {
            return new WheelPaintHolder(part, materialId, id);
        }

        public override bool Equals(BasePaintHolder other)
        {
            var otherPaint = other as WheelPaintHolder;
            return (otherPaint != null) amp;amp; (otherPaint.part == part) amp;amp; (otherPaint.materialId == materialId) amp;amp; (otherPaint.id == id);
        }
    }

    [ProtoContract]
    public class WheelCustomPaintHolder : BaseWheelPaintHolder, ICustomPaintHolder
    {
        [ProtoMember(1)]
        public HSBColor hsb { get; set; }

        public WheelCustomPaintHolder() { }
        public WheelCustomPaintHolder(WheelPaintPart part, int materialId, HSBColor hsb) : base(part, materialId)
        {
            this.hsb = hsb;
        }

        public override BaseWheelPaintHolder Copy()
        {
            return new WheelCustomPaintHolder(part, materialId, hsb);
        }

        public override bool Equals(BasePaintHolder other)
        {
            var otherPaint = other as WheelCustomPaintHolder;
            return (otherPaint != null) amp;amp; (otherPaint.part == part) amp;amp; (otherPaint.materialId == materialId) amp;amp; HSBColor.EqualsOpaque(otherPaint.hsb, hsb);
        }
    }

    [ProtoContract]
    [ProtoInclude(100, typeof(GlassPaintHolder)), ProtoInclude(200, typeof(GlassCustomPaintHolder))]
    public abstract class BaseGlassPaintHolder : BasePaintHolder
    {
        [ProtoMember(1)]
        public GlassPaintPart part { get; set; }
        
        protected override CarPaintType[] materials => CarPaintMaterials.Glass;

        public BaseGlassPaintHolder() { }

        public BaseGlassPaintHolder(GlassPaintPart part, int materialId) : base(materialId)
        {
            this.part = part;
        }

        public abstract BaseGlassPaintHolder Copy();
    }

    [ProtoContract]
    public class GlassPaintHolder : BaseGlassPaintHolder, IPaintHolder
    {
        [ProtoMember(1)]
        public int id { get; set; }

        public GlassPaintHolder() { }
        public GlassPaintHolder(GlassPaintPart part, int materialId, int id) : base(part, materialId)
        {
            this.id = id;
        }

        public override BaseGlassPaintHolder Copy()
        {
            return new GlassPaintHolder(part, materialId, id);
        }

        public override bool Equals(BasePaintHolder other)
        {
            var otherPaint = other as GlassPaintHolder;
            return (otherPaint != null) amp;amp; (otherPaint.materialId == materialId) amp;amp; (otherPaint.id == id);
        }
    }

    [ProtoContract]
    public class GlassCustomPaintHolder : BaseGlassPaintHolder, ICustomPaintHolder
    {
        [ProtoMember(1)]
        public HSBColor hsb { get; set; }

        public GlassCustomPaintHolder() { }
        public GlassCustomPaintHolder(GlassPaintPart part, int materialId, HSBColor hsb) : base(part, materialId)
        {
            this.hsb = hsb;
        }

        public override BaseGlassPaintHolder Copy()
        {
            return new GlassCustomPaintHolder(part, materialId, hsb);
        }

        public override bool Equals(BasePaintHolder other)
        {
            var otherPaint = other as GlassCustomPaintHolder;
            return (otherPaint != null) amp;amp; (otherPaint.materialId == materialId) amp;amp; HSBColor.EqualsOpaque(otherPaint.hsb, hsb);
        }
    }

    [ProtoContract]
    [ProtoInclude(100, typeof(SmokePaintHolder)), ProtoInclude(200, typeof(SmokeCustomPaintHolder))]
    public abstract class BaseSmokePaintHolder : BasePaintHolder
    {
        protected override CarPaintType[] materials => CarPaintMaterials.Smoke;

        public BaseSmokePaintHolder() { }
        public BaseSmokePaintHolder(int materialId) : base(materialId) { }

        public abstract BaseSmokePaintHolder Copy();
    }

    [ProtoContract]
    public class SmokePaintHolder : BaseSmokePaintHolder, IPaintHolder
    {
        [ProtoMember(1)]
        public int id { get; set; }

        public SmokePaintHolder() { }
        public SmokePaintHolder(int materialId, int id) : base(materialId)
        {
            this.id = id;
        }

        public override BaseSmokePaintHolder Copy()
        {
            return new SmokePaintHolder(materialId, id);
        }

        public override bool Equals(BasePaintHolder other)
        {
            var otherPaint = other as SmokePaintHolder;
            return (otherPaint != null) amp;amp; (otherPaint.materialId == materialId) amp;amp; (otherPaint.id == id);
        }
    }

    [ProtoContract]
    public class SmokeCustomPaintHolder : BaseSmokePaintHolder, ICustomPaintHolder
    {
        [ProtoMember(1)]
        public HSBColor hsb { get; set; }

        public SmokeCustomPaintHolder() { }
        public SmokeCustomPaintHolder(int materialId, HSBColor hsb) : base(materialId)
        {
            this.hsb = hsb;
        }

        public override BaseSmokePaintHolder Copy()
        {
            return new SmokeCustomPaintHolder(materialId, hsb);
        }

        public override bool Equals(BasePaintHolder other)
        {
            var otherPaint = other as SmokeCustomPaintHolder;
            return (otherPaint != null) amp;amp; (otherPaint.materialId == materialId) amp;amp; HSBColor.EqualsOpaque(otherPaint.hsb, hsb);
        }
    }

    [ProtoContract]
    [ProtoInclude(100, typeof(SuspensionPaintHolder)), ProtoInclude(200, typeof(SuspensionCustomPaintHolder))]
    public abstract class BaseSuspensionPaintHolder : BasePaintHolder
    {
        [ProtoMember(1)]
        public SuspensionPaintPart part { get; set; }

        protected override CarPaintType[] materials => CarPaintMaterials.Suspension;

        public BaseSuspensionPaintHolder() { }
        public BaseSuspensionPaintHolder(SuspensionPaintPart part, int materialId) : base(materialId)
        {
            this.part = part;
        }

        public override float GetCategoryCostCoefficient(CarSharedMeta carMeta)
        {
            return carMeta.GetPaintCategoryCostCoefficient(BodyPartType.Suspension);
        }

        public abstract BaseSuspensionPaintHolder Copy();
    }

    [ProtoContract]
    public class SuspensionPaintHolder : BaseSuspensionPaintHolder, IPaintHolder
    {
        [ProtoMember(1)]
        public int id { get; set; }

        public SuspensionPaintHolder() { }
        public SuspensionPaintHolder(SuspensionPaintPart part, int id, int materialId) : base(part, materialId)
        {
            this.id = id;
        }

        public override BaseSuspensionPaintHolder Copy()
        {
            return new SuspensionPaintHolder(part, id, materialId);
        }

        public override bool Equals(BasePaintHolder other)
        {
            var otherPaint = other as SuspensionPaintHolder;
            return (otherPaint != null) amp;amp; (otherPaint.materialId == materialId) amp;amp; (otherPaint.id == id);
        }
    }

    [ProtoContract]
    public class SuspensionCustomPaintHolder : BaseSuspensionPaintHolder, ICustomPaintHolder
    {
        [ProtoMember(1)]
        public HSBColor hsb { get; set; }

        public SuspensionCustomPaintHolder() { }
        public SuspensionCustomPaintHolder(SuspensionPaintPart part, HSBColor hsb, int materialId) : base(part, materialId)
        {
            this.hsb = hsb;
        }

        public override BaseSuspensionPaintHolder Copy()
        {
            return new SuspensionCustomPaintHolder(part, hsb, materialId);
        }

        public override bool Equals(BasePaintHolder other)
        {
            var otherPaint = other as SuspensionCustomPaintHolder;
            return (otherPaint != null) amp;amp; (otherPaint.materialId == materialId) amp;amp; HSBColor.EqualsOpaque(otherPaint.hsb, hsb);
        }
    }

    [ProtoContract]
    [ProtoInclude(100, typeof(InteriorPaintHolder)), ProtoInclude(200, typeof(InteriorCustomPaintHolder))]
    public abstract class BaseInteriorPaintHolder : BasePaintHolder
    {
        [ProtoMember(1)]
        public InteriorPaintPart part { get; set; }

        protected override CarPaintType[] materials => CarPaintMaterials.Interior;

        public BaseInteriorPaintHolder() { }
        public BaseInteriorPaintHolder(InteriorPaintPart part, int materialId) : base(materialId)
        {
            this.part = part;
        }

        public override float GetCategoryCostCoefficient(CarSharedMeta carMeta)
        {
            return carMeta.GetPaintCategoryCostCoefficient(BodyPartType.SeatLeft);
        }

        public abstract BaseInteriorPaintHolder Copy();
    }

    [ProtoContract]
    public class InteriorPaintHolder : BaseInteriorPaintHolder, IPaintHolder
    {
        [ProtoMember(1)]
        public int id { get; set; }

        public InteriorPaintHolder() { }
        public InteriorPaintHolder(InteriorPaintPart part, int id, int materialId) : base(part, materialId)
        {
            this.id = id;
        }

        public override BaseInteriorPaintHolder Copy()
        {
            return new InteriorPaintHolder(part, id, materialId);
        }

        public override bool Equals(BasePaintHolder other)
        {
            return (other is InteriorPaintHolder otherPaint) amp;amp; (otherPaint.materialId == materialId) amp;amp; (otherPaint.id == id);
        }
    }

    [ProtoContract]
    public class InteriorCustomPaintHolder : BaseInteriorPaintHolder, ICustomPaintHolder
    {
        [ProtoMember(1)]
        public HSBColor hsb { get; set; }

        public InteriorCustomPaintHolder() { }
        public InteriorCustomPaintHolder(InteriorPaintPart part, HSBColor hsb, int materialId) : base(part, materialId)
        {
            this.hsb = hsb;
        }

        public override BaseInteriorPaintHolder Copy()
        {
            return new InteriorCustomPaintHolder(part, hsb, materialId);
        }

        public override bool Equals(BasePaintHolder other)
        {
            return (other is InteriorCustomPaintHolder otherPaint) amp;amp; (otherPaint.materialId == materialId) amp;amp; HSBColor.EqualsOpaque(otherPaint.hsb, hsb);
        }
    }

    [ProtoContract]
    [ProtoInclude(100, typeof(GenericPaintHolder)), ProtoInclude(200, typeof(GenericCustomPaintHolder))]
    public abstract class BaseGenericPaintHolder : BasePaintHolder
    {
        protected override CarPaintType[] materials => CarPaintMaterials.Generic;

        public BaseGenericPaintHolder() { }
        public BaseGenericPaintHolder(int materialId) : base(materialId) { }

        public abstract BaseGenericPaintHolder Copy();
    }

    [ProtoContract]
    public class GenericPaintHolder : BaseGenericPaintHolder, IPaintHolder
    {
        [ProtoMember(1)]
        public int id { get; set; }

        public GenericPaintHolder() { }
        public GenericPaintHolder(int materialId, int id) : base(materialId)
        {
            this.id = id;
        }

        public override BaseGenericPaintHolder Copy()
        {
            return new GenericPaintHolder(materialId, id);
        }

        public override bool Equals(BasePaintHolder other)
        {
            var otherPaint = other as GenericPaintHolder;
            return (otherPaint != null) amp;amp; (otherPaint.materialId == materialId) amp;amp; (otherPaint.id == id);
        }
    }

    [ProtoContract]
    public class GenericCustomPaintHolder : BaseGenericPaintHolder, ICustomPaintHolder
    {
        [ProtoMember(1)]
        public HSBColor hsb { get; set; }

        public GenericCustomPaintHolder() { }
        public GenericCustomPaintHolder(int materialId, HSBColor hsb) : base(materialId)
        {
            this.hsb = hsb;
        }

        public override BaseGenericPaintHolder Copy()
        {
            return new GenericCustomPaintHolder(materialId, hsb);
        }

        public override bool Equals(BasePaintHolder other)
        {
            var otherPaint = other as GenericCustomPaintHolder;
            return (otherPaint != null) amp;amp; (otherPaint.materialId == materialId) amp;amp; HSBColor.EqualsOpaque(otherPaint.hsb, hsb);
        }
    }

    [ProtoMember(1)]
    public List<BaseBodyPaintHolder> bodyPaints = null;
    [ProtoMember(2)]
    public List<BaseWheelPaintHolder> frontWheelPaints = null;
    [ProtoMember(3)]
    public List<BaseWheelPaintHolder> rearWheelPaints = null;
    [ProtoMember(4)]
    public List<BaseSuspensionPaintHolder> suspensionPaints = null;
    [ProtoMember(5)]
    public BaseGlassPaintHolder glassPaint = null;
    [ProtoMember(6)]
    public BaseSmokePaintHolder smokePaint = null;
    [ProtoMember(14)]
    public BaseGenericPaintHolder genericPaint = null;
    [ProtoMember(15)]
    public List<BaseInteriorPaintHolder> interiorPaints = null;
    [ProtoMember(16)]
    public List<BaseGlassPaintHolder> lightGlassesPaints = null;
    [ProtoMember(7)]
    public Dictionary<WheelAxles, int> wheelTires = null;

    [ProtoMember(8)]
    public List<BodyPartHolder> bodyParts = null;
    [ProtoMember(9)]
    public int frontRimPartId = 1;
    [ProtoMember(10)]
    public int rearRimPartId = 1;
    [ProtoMember(11)]
    public int bodyKitId;

    [ProtoMember(12)]
    public List<VinylLayer> vinylLayers = null;

    [ProtoMember(13)]
    public string workshopItemId = null;

    public VisualSettings()
    {
        bodyPaints = new List<BaseBodyPaintHolder>();
        rearWheelPaints = new List<BaseWheelPaintHolder>();
        frontWheelPaints = new List<BaseWheelPaintHolder>();
        suspensionPaints = new List<BaseSuspensionPaintHolder>();
        interiorPaints = new List<BaseInteriorPaintHolder>();
        lightGlassesPaints = new List<BaseGlassPaintHolder>();
        bodyParts = new List<BodyPartHolder>();
        vinylLayers = new List<VinylLayer>();
        wheelTires = new Dictionary<WheelAxles, int>();
    }

    public VisualSettings(VisualSettings copyFrom)
    {
        bodyPaints = new List<BaseBodyPaintHolder>(copyFrom.bodyPaints);
        rearWheelPaints = new List<BaseWheelPaintHolder>(copyFrom.rearWheelPaints);
        frontWheelPaints = new List<BaseWheelPaintHolder>(copyFrom.frontWheelPaints);
        suspensionPaints = new List<BaseSuspensionPaintHolder>(copyFrom.suspensionPaints);
        interiorPaints = new List<BaseInteriorPaintHolder>(copyFrom.interiorPaints);
        lightGlassesPaints = new List<BaseGlassPaintHolder>(copyFrom.lightGlassesPaints);
        bodyParts  = new List<BodyPartHolder>(copyFrom.bodyParts);
        vinylLayers = new List<VinylLayer>(copyFrom.vinylLayers);
        wheelTires = new Dictionary<WheelAxles, int>(copyFrom.wheelTires);
        glassPaint = copyFrom.glassPaint;
        smokePaint = copyFrom.smokePaint;
        genericPaint = copyFrom.genericPaint;
        frontRimPartId = copyFrom.frontRimPartId;
        rearRimPartId = copyFrom.rearRimPartId;
        bodyKitId = copyFrom.bodyKitId;
        workshopItemId = copyFrom.workshopItemId;
    }

}
 

Я сгенерировал файл .proto с помощью Serializer.GetProto<VisualSettings>() и генерирую классы Java (для второго приложения), используя этот файл .proto.
Файл Proto, созданный protobuf-net:

 syntax = "proto2";

package visual_settings;

option java_multiple_files = true;
option java_package = "com.test";
option java_outer_classname = "VisualSettingsProto";

message BaseBodyPaintHolder {
  optional BodyPartType part = 1 [default = Chassis];
  // the following represent sub-types; at most 1 should have a value
  optional BodyPaintHolder BodyPaintHolder = 100;
  optional BodyCustomPaintHolder BodyCustomPaintHolder = 200;
}
message BaseGenericPaintHolder {
  // the following represent sub-types; at most 1 should have a value
  optional GenericPaintHolder GenericPaintHolder = 100;
  optional GenericCustomPaintHolder GenericCustomPaintHolder = 200;
}
message BaseGlassPaintHolder {
  optional GlassPaintPart part = 1 [default = Glasses];
  // the following represent sub-types; at most 1 should have a value
  optional GlassPaintHolder GlassPaintHolder = 100;
  optional GlassCustomPaintHolder GlassCustomPaintHolder = 200;
}
message BaseInteriorPaintHolder {
  optional InteriorPaintPart part = 1 [default = SteeringWheelAlcantar];
  // the following represent sub-types; at most 1 should have a value
  optional InteriorPaintHolder InteriorPaintHolder = 100;
  optional InteriorCustomPaintHolder InteriorCustomPaintHolder = 200;
}
message BasePaintHolder {
  optional int32 materialId = 1 [default = 0];
  // the following represent sub-types; at most 1 should have a value
  optional BaseBodyPaintHolder BaseBodyPaintHolder = 100;
  optional BaseWheelPaintHolder BaseWheelPaintHolder = 200;
  optional BaseGlassPaintHolder BaseGlassPaintHolder = 300;
  optional BaseSmokePaintHolder BaseSmokePaintHolder = 400;
  optional BaseSuspensionPaintHolder BaseSuspensionPaintHolder = 500;
  optional BaseInteriorPaintHolder BaseInteriorPaintHolder = 600;
}
message BaseSmokePaintHolder {
  // the following represent sub-types; at most 1 should have a value
  optional SmokePaintHolder SmokePaintHolder = 100;
  optional SmokeCustomPaintHolder SmokeCustomPaintHolder = 200;
}
message BaseSuspensionPaintHolder {
  optional SuspensionPaintPart part = 1 [default = Arm];
  // the following represent sub-types; at most 1 should have a value
  optional SuspensionPaintHolder SuspensionPaintHolder = 100;
  optional SuspensionCustomPaintHolder SuspensionCustomPaintHolder = 200;
}
message BaseWheelPaintHolder {
  optional WheelPaintPart part = 1 [default = SpokeFront];
  // the following represent sub-types; at most 1 should have a value
  optional WheelPaintHolder WheelPaintHolder = 100;
  optional WheelCustomPaintHolder WheelCustomPaintHolder = 200;
}
message BodyCustomPaintHolder {
  optional HSBColor hsb = 1;
}
message BodyPaintHolder {
  optional int32 id = 1 [default = 0];
}
message BodyPartHolder {
  optional BodyPartType type = 1 [default = Chassis];
  optional int32 id = 2 [default = 0];
}
enum BodyPartType {
  Chassis = 0;
  BumperFront = 1;
  BumperRear = 2;
  Skirts = 3;
  Doors = 4;
  Roof = 5;
  Mirrors = 6;
  Bonnet = 7;
  Trunk = 8;
  Spoiler = 9;
  LightsFront = 10;
  LightsRear = 11;
  Exhaust = 12;
  Cage = 13;
  Suspension = 14;
  Interior = 15;
  SeatLeft = 16;
  SeatRight = 17;
  SteeringWheel = 18;
  Handbrake = 19;
  Shifter = 20;
  Dashboard = 21;
  Engine = 22;
  BlobShadow = 23;
}
message GenericCustomPaintHolder {
  optional HSBColor hsb = 1;
}
message GenericPaintHolder {
  optional int32 id = 1 [default = 0];
}
message GlassCustomPaintHolder {
  optional HSBColor hsb = 1;
}
message GlassPaintHolder {
  optional int32 id = 1 [default = 0];
}
enum GlassPaintPart {
  Glasses = 0;
  FrontLight = 1;
  RearLight = 2;
  FogLight = 3;
}
message HSBColor {
  optional float h = 1 [default = 0];
  optional float s = 2 [default = 0];
  optional float b = 3 [default = 0];
  optional float a = 4 [default = 0];
}
message InteriorCustomPaintHolder {
  optional HSBColor hsb = 1;
}
message InteriorPaintHolder {
  optional int32 id = 1 [default = 0];
}
enum InteriorPaintPart {
  SteeringWheelAlcantar = 0;
  SteeringWheelStrings = 1;
  SteeringWheelSpokes = 2;
  LeftSeatBase = 3;
  LeftSeatBottom = 4;
  RightSeatBase = 5;
  RightSeatBottom = 6;
  GearBoxHandle = 7;
  HandbrakeHandle = 8;
}
message KeyValuePair_WheelAxles_Int32 {
  optional WheelAxles Key = 1;
  optional int32 Value = 2;
}
message SmokeCustomPaintHolder {
  optional HSBColor hsb = 1;
}
message SmokePaintHolder {
  optional int32 id = 1 [default = 0];
}
message SuspensionCustomPaintHolder {
  optional HSBColor hsb = 1;
}
message SuspensionPaintHolder {
  optional int32 id = 1 [default = 0];
}
enum SuspensionPaintPart {
  Arm = 0;
  Rack = 1;
  Spring = 2;
  BrakeCaliper = 3;
}
message VinylLayerSurrogate {
  optional int32 rawId = 1 [default = 0];
  optional float angle = 2 [default = 0];
  optional bool isSymmetry = 3 [default = false];
  optional bool isHorizontalFlip = 4 [default = false];
  optional bool isVerticalFlip = 5 [default = false];
  optional bool isPassThrough = 6 [default = false];
  optional bytes colors = 7;
  optional bytes transform = 8;
  optional int32 groupMask = 9 [default = 0];
  optional float clipMaskShift = 10 [default = 0];
}
message VisualSettings {
  repeated BasePaintHolder bodyPaints = 1;
  repeated BasePaintHolder frontWheelPaints = 2;
  repeated BasePaintHolder rearWheelPaints = 3;
  repeated BasePaintHolder suspensionPaints = 4;
  optional BasePaintHolder glassPaint = 5;
  optional BasePaintHolder smokePaint = 6;
  repeated KeyValuePair_WheelAxles_Int32 wheelTires = 7;
  repeated BodyPartHolder bodyParts = 8;
  optional int32 frontRimPartId = 9 [default = 0];
  optional int32 rearRimPartId = 10 [default = 0];
  optional int32 bodyKitId = 11 [default = 0];
  repeated VinylLayerSurrogate vinylLayers = 12;
  optional string workshopItemId = 13;
  optional BaseGenericPaintHolder genericPaint = 14;
  repeated BasePaintHolder interiorPaints = 15;
  repeated BasePaintHolder lightGlassesPaints = 16;
}
enum WheelAxles {
  Front = 0;
  Rear = 1;
}
message WheelCustomPaintHolder {
  optional HSBColor hsb = 1;
}
message WheelPaintHolder {
  optional int32 id = 1 [default = 0];
}
enum WheelPaintPart {
  SpokeFront = 0;
  SpokeRear = 1;
  RimFront = 2;
  RimRear = 3;
}

 

С помощью сгенерированных классов java я могу десериализовать данные из C# без проблем, но когда я сериализую данные (настройка визуализации) на стороне Java, C# не смог десериализовать их, я получаю ошибку:
ProtoException: No parameterless constructor found for BasePaintHolder .
Но java может десериализовать собственные сериализованные данные.
Я подозреваю, что шаблон protobuf-net сгенерирован .proto неправильно. Могу ли я улучшить свой файл .proto? Или я делаю что-то не так?

Комментарии:

1. Я думаю, что поддержка полиморфизма-это расширение, и я не уверен, насколько хорошо это поддерживается в Java. Надеюсь, Марк Гравелл увидит это и предоставит более подробную информацию.

2. @JonasH нет, они очень ненадежны и почти никогда не отвечают на вопросы

Ответ №1:

Это происходит из-за наследства, в принципе; наследование-это не концепция, что protobuf поддерживает, так что protobuf-чистая модели наследования через вложенных объектов, чтобы избежать некоторых сложностей при сериализации этого, protobuf-net, который всегда начинается с написания наследование части первая — это так: при сериализации BasePaintHolder , он может сериализовать поля 400 (суб-тип данных BaseSmokePaintHolder ), затем 1 поле ( materialId ). Это означает, что когда дело доходит до десериализации, у него есть очевидный путь построения, т. Е. К тому времени, когда он получает данные поля, он уже создал окончательный конкретный тип.

Это нормально для сценариев protobuf-net-protobuf-net, но когда мы работаем с одними и теми же данными в Java, он не знает об этом или не заботится об этом и выбирает сериализацию в порядке возрастания полей, т. е. поле 1, затем поле 400. В спецификации явно указано, что поля могут быть не в порядке, но Java может делать все, что захочет.

Итак: теперь мы возвращаем эти данные обратно в protobuf-net, и сначала мы видим поле 1; в этот момент мы понятия не имеем, каким будет окончательный тип, и некуда (пока) вставлять данные. Не имея лучших вариантов, библиотека пытается использовать базовый тип BasePaintHolder в качестве заполнителя, пока не сможет принимать лучшие решения , но оказывается, что этот тип есть abstract , так что: даже это не удается.

Итак: вот почему и некоторая предыстория. Что мы можем сделать?

Ну, первое , что мы могли бы попробовать, — это удалить abstract его, сделав его технически конструктивным. Чтобы предотвратить случайное создание экземпляров внешним кодом, вы также можете создать конструкторы protected , internal , или private protected (что означает пересечение protected и internal ). Мы также могли бы попробовать использовать SkipConstructor=true модификатор вкл [ProtoContract] .

Если это не работает: возможно, необходимо, чтобы в основном работать с 2 различных объектных моделей, одна из которых проста — по сути больше похоже на Java-версии, возможно, выполнив свою схему по https://protogen.marcgravell.com/ — и тот, который имеет наследству; использовать простые версия для десериализации (и при необходимости сериализации, хотя это не должно волновать), а затем повторно отобразить данные в свой собственный код для фактической модели. Другой вариант для меня-найти способ сделать все это волшебным образом и автоматически; что: не маленькая работа.

Комментарии:

1. Спасибо! Способ удаления абстрактных классов работает нормально.