Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Efficient Byte Data Formatting with Custom Jackson Annotations

Tech May 10 3

Understanding Byte Data Units

A byte (abbreviated as B) is the fundamental unit of digital information storage, consisting of 8 bits. In ASCII encoding, a single byte can represent standard English characters, numbers, punctuation, and control characters. Modern systems commonly use larger units for practical measurement:

While databases typically store raw byte values for precision, user interfaces require human-readable formats. This creates a common need for conversion between storage and display formats.

Implementation Scenario

Consider a cloud storage system where user data usage is stored in bytes but must be displayed in appropriate units. Two API endpoints demonstrate this requirement:

// Retrieves user storage usage
GET /api/user/storage/123

Response:
{
  "userId": 123,
  "usage": "2.3 GB"
}

// Updates user storage limit
POST /api/user/storage
{
  "userId": 123,
  "limit": "5.0 TB"
}

Custom Annotation Solution

Using Jackson's extensible serialization framework, we create a custom annotation to handle byte conversions automatically:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@JsonSerialize(using = ByteSerializer.class)
@JsonDeserialize(using = ByteDeserializer.class)
public @interface ByteFormat {
    int precision() default 2;
}

Serialization Implementation

The serializer converts numeric byte values to formatted strings with appropriate units:

public class ByteSerializer extends JsonSerializer<Number> {
    private int precision;
    
    public ByteSerializer(int precision) {
        this.precision = precision;
    }
    
    @Override
    public void serialize(Number value, JsonGenerator gen, 
                         SerializerProvider provider) throws IOException {
        if (value == null) return;
        String formatted = ByteConverter.format(value.longValue(), precision);
        gen.writeString(formatted);
    }
}

Deserialization Implementation

The deserializer converts formatted strings back to raw byte values:

public class ByteDeserializer extends JsonDeserializer<Number> {
    @Override
    public Number deserialize(JsonParser parser, 
                             DeserializationContext context) throws IOException {
        String text = parser.getText();
        return ByteConverter.parse(text);
    }
}

Conversion Utility

The core conversion logic handles both formatting and parsing:

public class ByteConverter {
    private static final long KB = 1024L;
    private static final long MB = KB * 1024;
    private static final long GB = MB * 1024;
    private static final long TB = GB * 1024;
    
    public static String format(long bytes, int decimalPlaces) {
        if (bytes >= TB) {
            return String.format("%." + decimalPlaces + "f TB", bytes / (double) TB);
        }
        if (bytes >= GB) {
            return String.format("%." + decimalPlaces + "f GB", bytes / (double) GB);
        }
        if (bytes >= MB) {
            return String.format("%." + decimalPlaces + "f MB", bytes / (double) MB);
        }
        if (bytes >= KB) {
            return String.format("%." + decimalPlaces + "f KB", bytes / (double) KB);
        }
        return bytes + " B";
    }
    
    public static long parse(String formatted) {
        String clean = formatted.trim().toUpperCase();
        if (clean.endsWith("TB")) {
            double value = Double.parseDouble(clean.replace("TB", ""));
            return (long) (value * TB);
        }
        if (clean.endsWith("GB")) {
            double value = Double.parseDouble(clean.replace("GB", ""));
            return (long) (value * GB);
        }
        if (clean.endsWith("MB")) {
            double value = Double.parseDouble(clean.replace("MB", ""));
            return (long) (value * MB);
        }
        if (clean.endsWith("KB")) {
            double value = Double.parseDouble(clean.replace("KB", ""));
            return (long) (value * KB);
        }
        if (clean.endsWith("B")) {
            return Long.parseLong(clean.replace("B", ""));
        }
        return Long.parseLong(clean);
    }
}

Usage Example

Apply the annotation to DTO fields for automatic conversion:

public class StorageInfo {
    private Long userId;
    
    @ByteFormat(precision = 1)
    private Long currentUsage;
    
    @ByteFormat(precision = 2)
    private Long storageLimit;
}

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

SBUS Signal Analysis and Communication Implementation Using STM32 with Fus Remote Controller

Overview In a recent project, I utilized the SBUS protocol with the Fus remote controller to control a vehicle's basic operations, including movement, lights, and mode switching. This article is aimed...

Comprehensive Guide to Hive SQL Syntax and Operations

This article provides a detailed walkthrough of Hive SQL, categorizing its features and syntax for practical use. Hive SQL is segmented into the following categories: DDL Statements: Operations on...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.