4

I have two related questions:

  1. I'm able to send byte[] over the network for this class:
class Employee implements Serializable{
    byte[] avroBytes, //avro data in byte[] array
    String name
}

In my test case, using MockMvc, I'm able to de-serialize it, and then cast it to Employee object because my test case can use the same POJO from code. However the client will not have this POJO or class information. After it receives the bytes, how can it reconstruct this POJO(or whatever is the equivalent in other languages) or Object? Do I need to send in some class information in the header? It's possible that the client is using Python or some other language, so I need a way for this class information to be generic.

In my test case this works:

 Employee res = (Employee ) SerializationUtils.deserialize(result.getResponse().getContentAsByteArray());

How will client cast the de-serialized bytes to Employee if they don't have this POJO/information? I could do it in my test case because my code has the Employee class in code.

Additional information to comments:

I serialized it using org.springframework.util.SerializationUtils serialize() method

user2441441
  • 1,237
  • 4
  • 24
  • 45
  • 2
    Please ask *one* question per post. It's not immediately clear to me whether this is really one question or two - I'd expect Avro to have a sort of "dynamic" way of deserializing data (the equivalent of JsonObject for example) but that's not the same as your POJO question. – Jon Skeet Jun 17 '22 at 07:27
  • Removed that second question – user2441441 Jun 17 '22 at 07:40
  • 1
    You serialized it how? – user207421 Jun 17 '22 at 07:46
  • I used org.springframework.util.SerializationUtils.serialize() method – user2441441 Jun 17 '22 at 07:50
  • @JonSkeet Would you know how to go about this? How can the Client re-construct the object back(they can be using Python, Java, etc) from the byte[] array? I have seen samples online, but in those the Client casts the Object to the POJO, knowing the POJO in advence. Or can the Client not have the POJO information, and still retrieve the fields in the Object? – user2441441 Jun 17 '22 at 21:25
  • I'm afraid I'm not familiar enough with Avro to know the answer - I was trying to get your question into an appropriate shape for SO. – Jon Skeet Jun 18 '22 at 06:42
  • Avro is the inside body, the message is sent in byte[] that needs to be reconstructed to a (POJO) object first. I'm trying to understand about the POJO outer object reconstruction on the client side – user2441441 Jun 18 '22 at 21:01
  • Please check [How to deserialize an object of unknown class](https://stackoverflow.com/questions/19258433/how-to-deserialize-an-object-of-unknown-class) – Eskandar Abedini Jun 21 '22 at 05:55
  • Use Jackson APIs for your purpose. – medgai Jun 24 '22 at 15:29
  • How are you sending it over the network? Using a socket? JSON Web Service? Soap Web Service? Answers can be differents depending on that. – CaptainPyscho Jun 25 '22 at 17:46

5 Answers5

5

Jackson can resolve your problem. It has the ability to convert object to byte array and then convert from byte array to another object with a similar structure.
Conversion will be performed in next way:

Object1 -> JSON -> byte[]
byte[] -> JSON -> Object2

Example:

public class TestClass {
    @Test
    public void methodTest() throws IOException {
        Employee1 employee1 = new Employee1();
        employee1.bytes = new byte[] {1, 2, 3};
        employee1.name = "name";

        ObjectMapper objectMapper = new ObjectMapper();
        //convert Employee to byte array
        byte[] serialized = objectMapper.writeValueAsBytes(employee1);

        //convert from byte array to another object with a similar structure
        Employee2 employee2 = objectMapper.reader().readValue(serialized, Employee2.class);

        Assert.assertArrayEquals(employee1.bytes, employee2.bytes);
        Assert.assertEquals(employee1.name, employee2.name);
    }
}

public class Employee1 implements Serializable {
   public byte[] bytes;
   public String name;
}

public class Employee2 implements Serializable {
    public byte[] bytes;
    public String name;
}

Jackson provides the ability to specify an exact type for conversion. It is achieved thru intermediate JSON.

Eugene
  • 5,269
  • 2
  • 14
  • 22
  • What will be the structure of Employee2 at client side? Does server need to provide it? Or documentation? If not, then how can the client know what to cast it to? – user2441441 Jun 20 '22 at 22:15
  • I have added structure for Employee1 and Employee2. The client and server objects should have the same structure, it is not the same objects but with the same structure. Server does not need to provide it, the structure is injected into the byte array, because you are converting not object but JSON to byte array, this is the main trik – Eugene Jun 20 '22 at 22:37
  • Main requirement of the solution is that client and server should have dependency on jackson. – Eugene Jun 20 '22 at 22:39
  • Also if you want to have some different structure of object at the client jackson provides a lot functionality for deserialization – Eugene Jun 20 '22 at 22:41
  • In this case, the client needs to know the structure of the class, which it does by defining Employee2(?) – user2441441 Jun 21 '22 at 00:07
  • yes, client needs to create own class similar which is defined at the server – Eugene Jun 21 '22 at 00:26
3

If you need POJO on the client side, you need to share generated code that the schema produce. If you don't need POJO you can populate GenericRecord directly with the schema.

UPDATE

Schema schema = new Schema.Parser().parse(new File("Employee.avsc"));    DatumReader<GenericRecord> datumReader = new GenericDatumReader<GenericRecord>(schema);
Decoder decoder = DecoderFactory.get().directBinaryDecoder(result.getResponse().getContentAsByteArray(), null);
GenericRecord gr= datumReader.read(null, decoder);
Mr_Thorynque
  • 1,749
  • 1
  • 20
  • 31
  • 'need to share generated code that the schema produce. If you don't need POJO you can populate GenericRecord directly with the schema.' How do I do both? – user2441441 Jun 19 '22 at 23:04
  • Why you need to do both ? If you have POJO classes it's you don't need to process manually the schema. – Mr_Thorynque Jun 24 '22 at 09:47
1

I think this is a more generic question about SOA (service-oriented architecture) architecture and how it works. so when it comes to producing and consuming messages between two brokers it needs some kind of interoperability. so in this case, from the beginning, we had a lot of frameworks and tools to achieve these use cases, starting with CORBA, and RPC (creating stubs stubs to consume the service from outside), However quoting "The client will not have this POJO or class information." -> This statement is about more of Serilization vs Marshaling

so for your use case assuming this is a REST service (than SOAP), you can use consuming types such as application/(json, etc..). please see more about consuming a rest service

MaxExplode
  • 1,977
  • 2
  • 17
  • 27
0
  • if "sending byte[]" isn't necessary, just send data in format of JSON / XML / any-random-middle-format
    • String is just an another kind of byte[]
  • java.io.Serializable / Protobuf lib / any-random-serialization-lib
Firok
  • 269
  • 1
  • 6
  • My response contains avro byte[] though, and look like JSON/XML doesn't support it. Should I send in Avro again then? – user2441441 Jun 17 '22 at 14:04
  • What's special about Avro? Why can't this structure just be represented as a JSON string? – Christopher Schneider Jun 17 '22 at 14:32
  • Because I thought JSON doesn't support byte[] array? And I need to send it in the response – user2441441 Jun 17 '22 at 16:51
  • @user2441441 You could simply convert between JSON String and byte[] via `str.getBytes(StandardCharsets.UTF_8)` and `new String(bytes, StandardCharsets.UTF_8)`. If you do need store some field of binary data, just transform them into base64 code String first, or any BSON lib is okay. – Firok Jun 20 '22 at 01:41
  • uh sorry, I didn't follow I think. I want to send bytes for avroData for compression reasons. – user2441441 Jun 20 '22 at 19:58
-1

Client could use a Map<String, Object> or equivalent in ther programming language.

CaptainPyscho
  • 338
  • 1
  • 7