Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Efficient Byte Data Formatting with Custom Jackson Annotations

Tech May 10 12

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 represant standard English characters, numbers, punctuation, and control characters. Modern systems commonly use larger units for practical measurement:

Unit Abbreviation Conversion
Kilobyte KB 1 KB = 1024 B
Megabyte MB 1 MB = 1024 KB
Gigabyte GB 1 GB = 1024 MB
Terabyte TB 1 TB = 1024 GB

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.

Implemantation 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...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

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