Good day! My Api returns byte variable like this "..." but retrofit in my android application can read only like this [...] how can i change response.
Entity:
@Entity
@Table(name = "book")
public class bookEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long books_id;
private String title;
private String description;
@Column(columnDefinition = "LONGBLOB")
private byte[] cover;
Service:
public Iterable<bookEntity> findAll()
{
return bookRepository.findAll();
}
Controller:
@GetMapping
public ResponseEntity getAllBook()
{
return ResponseEntity.ok(bookService.findAll());
}
Answers
It seems like you're facing an issue with how Retrofit is serializing the byte array returned by your API. Retrofit by default uses Gson or Moshi for JSON serialization and deserialization, and when it encounters a byte array, it serializes it as a JSON array ([...]
).
To address this issue, you can implement a custom JSON serializer and deserializer for the byte array in Retrofit. Here's how you can do it:
-
Create Custom Converter Factory: Create a custom converter factory that handles the serialization and deserialization of byte arrays.
-
Implement JSON Serializer and Deserializer: Implement custom JSON serializer and deserializer classes for byte arrays.
-
Register Converter Factory with Retrofit: Register the custom converter factory with Retrofit to use it for serialization and deserialization.
Here's an example implementation:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;
import java.lang.reflect.Type;
public class ByteArrayConverterFactory extends Converter.Factory {
public static ByteArrayConverterFactory create() {
return new ByteArrayConverterFactory();
}
private ByteArrayConverterFactory() {
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, java.lang.annotation.Annotation[] annotations, Retrofit retrofit) {
if (type == byte[].class) {
return ByteArrayResponseBodyConverter.INSTANCE;
}
return null;
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type, java.lang.annotation.Annotation[] parameterAnnotations, java.lang.annotation.Annotation[] methodAnnotations, Retrofit retrofit) {
if (type == byte[].class) {
return ByteArrayRequestBodyConverter.INSTANCE;
}
return null;
}
private static class ByteArrayResponseBodyConverter implements Converter<ResponseBody, byte[]> {
static final ByteArrayResponseBodyConverter INSTANCE = new ByteArrayResponseBodyConverter();
@Override
public byte[] convert(ResponseBody value) {
return value.bytes();
}
}
private static class ByteArrayRequestBodyConverter implements Converter<byte[], RequestBody> {
static final ByteArrayRequestBodyConverter INSTANCE = new ByteArrayRequestBodyConverter();
@Override
public RequestBody convert(byte[] value) {
return RequestBody.create(value, MediaType.get("application/octet-stream"));
}
}
}
To use this custom converter factory with Retrofit, you would add it when building your Retrofit instance:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addConverterFactory(ByteArrayConverterFactory.create())
.build();
With this setup, Retrofit should now properly serialize and deserialize byte arrays without converting them to JSON arrays.