Status
Current state: Under Discussion [One of "Under Discussion", "Accepted", "Rejected"] Accepted (vote thread)
Discussion thread: here
JIRA: KAFKA-6923
...
Code Block |
---|
language | java |
---|
title | Serializer |
---|
linenumbers | true |
---|
|
public interface Serializer<T> extends Closeable {
void configure(Map<String, ?> configs, boolean isKey);
default byte[] serialize(String topic, T data) {
return new byte[0];
}
default byte[] serialize(String topic, Headers headers, T data) { // This is the new method
return serialize(topic, data);
}
@Override
void close();
} |
...
Code Block |
---|
language | java |
---|
title | Deserializer |
---|
linenumbers | true |
---|
|
public interface Deserializer<T> extends Closeable {
void configure(Map<String, ?> configs, boolean isKey);
default T deserialize(String topic, byte[] data) {
return null;
}
default T deserialize(String topic, Headers headers, byte[] data) { // This is the new method
return deserialize(topic, data);
}
@Override
void close();
} |
...
Review existing unit tests and system tests.
Rejected Alternatives
...
Manual verification of binary compatibility: existing ExtendedSerializer implementations should work without recompiling the application.
Rejected Alternatives
The code examples here are made with the Deserializer
class but they are completely valid for the Serializer
as well.
Default Implementations for the "headerless" methods
There are options to provide a default implementation: return a dummy value or throw an exception as shown below. This means that we'll have an interface where there are no methods enforced. Furthermore we should somehow suggest users that which method should they implement. To achieve this we could deprecate the 2 parameter ("headerless") method but this would litter the code base with warnings as we're still using this method in a lot of places (like the serializers and deserializers).
Code Block |
---|
language | java |
---|
title | Serializer |
---|
linenumbers | true |
---|
|
public interface Serializer<T> extends Closeable {
void configure(Map<String, ?> configs, boolean isKey);
@Deprecated
default byte[] serialize(String topic, T data) {
return new byte[0];
// throw new UnsupportedOperationException("Method not implemented");
}
default byte[] serialize(String topic, Headers headers, T data) { // This is the new method
return serialize(topic, data);
}
@Override
void close();
} |
Code Block |
---|
language | java |
---|
title | Deserializer |
---|
linenumbers | true |
---|
|
public interface Deserializer<T> extends Closeable {
void configure(Map<String, ?> configs, boolean isKey);
@Deprecated
default T deserialize(String topic, byte[] data) {
return null;
// throw new UnsupportedOperationException("Method not implemented");
}
default T deserialize(String topic, Headers headers, byte[] data) { // This is the new method
return deserialize(topic, data);
}
@Override
void close();
} |
Propagate to more complicated
We could propagate the method calls to the deserialize(String,Headers,byte[])
method. The drawback here is that it wouldn't be backward compatible as the ExtendedDeserializer just did the opposite thing: it propagated the deserialize(String,byte[])
method from the deserialize(String,Headers,byte[])
method.
Code Block |
---|
language | java |
---|
title | Propagate to more complicated |
---|
|
public interface Deserializer<T> extends Closeable {
default T deserialize(String topic, byte[] data) {
return deserialize(topic, null, data);
}
default T deserialize(String topic, Headers headers, byte[] data) {
return null;
}
} |
Headers as parameter
In this version we'd make sure that setHeaders
is called right before deserialize
(or the same goes for serialize
). The drawback of this is that we'd force implementations to maintain state.
Code Block |
---|
language | java |
---|
title | Setter for Headers |
---|
|
public interface Deserializer<T> extends Closeable {
void setHeaders(Headers headers);
default T deserialize(String topic, byte[] data) {
return null;
}
} |
Circular-referencing methods
This implementation is pretty good if the user overrides one (or both) the methods, however in the case where the default implementation is used for both of them, we'll get into a circular method reference and eventually a stack overflow.
Code Block |
---|
language | java |
---|
title | Circular referencing methods |
---|
|
public interface Deserializer<T> extends Closeable {
default T deserialize(String topic, byte[] data) {
return deserialize(topic, null, data);
}
default T deserialize(String topic, Headers headers, byte[] data) {
return deserialize(topic, data);
}
} |