Backend Development 17 min read

Design and Implementation of a Lightweight Data Translation Framework for Java Backend Applications

This article introduces a lightweight, extensible Java framework that uses custom annotations to translate relational data, dictionaries, collections, and nested objects, detailing its background, architecture, core annotation design, usage examples, advanced features, Spring Boot integration, ORM support, and provides the open‑source repository link.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Design and Implementation of a Lightweight Data Translation Framework for Java Backend Applications

1. Background

In many backend projects, developers often need to translate data—e.g., returning related query results to the frontend. Typical ORM code looks like this:

// query table A
List<A> alist = aDao.findAll(query);
// extract B ids from A
List<Long> bids = alist.stream().map(a::bid).toList();
// query table B and map to id
Map<Long,B> bMap = bDao.findAll(bids).stream().toMap(b::id, x->x);
// assemble data
...

Such repetitive logic motivates the creation of a dedicated translation framework.

The existing easy_trans framework solves the problem but has drawbacks: it is heavy (introduces Redis cache), requires entities to implement its interfaces, and generates translated fields in a map that is not convenient for Swagger documentation.

Therefore, a custom lightweight framework is developed.

2. Architecture Design

The design follows the idea of Spring Validation: custom annotations drive the translation process.

Core annotation definition:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface Trans {
    /** field to translate */
    String trans() default "";
    /** key field to extract */
    String key() default "";
    /** repository that provides translation data */
    Class
using();
}

3. Advantages

Core source code is only a few hundred lines with no external dependencies.

Highly extensible; extending logic only requires implementing TransRepository .

Supports database translation, dictionary translation, collection translation, nested translation, etc.

Parallel translation of different fields for high performance.

4. Basic Usage

Add the Maven dependency:

<dependency>
    <groupId>io.github.orangewest</groupId>
    <artifactId>easy-trans-core</artifactId>
    <version>0.0.3</version>
</dependency>

Define DTOs (Teacher, Subject, User) and annotate fields that need translation with @Trans or @DictTrans :

@Data
@AllArgsConstructor
@NoArgsConstructor
public class TeacherDto {
    private Long id;
    private String name;
    private Long subjectId;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SubjectDto {
    private Long id;
    private String name;
}
@Data
public class UserDto {
    private Long id;
    private String name;
    private String sex;
    @DictTrans(trans = "sex", group = "sexDict")
    private String sexName;
    private String job;
    @DictTrans(trans = "job", group = "jobDict")
    private String jobName;
    private Long teacherId;
    @Trans(trans = "teacherId", key = "name", using = TeacherTransRepository.class)
    private String teacherName;
    @Trans(trans = "teacherId", key = "subjectId", using = TeacherTransRepository.class)
    private Long subjectId;
    @Trans(using = SubjectTransRepository.class, trans = "subjectId", key = "name")
    private String subjectName;
    // constructor omitted for brevity
}

Implement the translation repositories:

public class TeacherTransRepository implements TransRepository {
    @Override
    public Map
getTransValueMap(List
transValues, Annotation transAnno) {
        return getTeachers().stream()
            .filter(t -> transValues.contains(t.getId()))
            .collect(Collectors.toMap(TeacherDto::getId, t -> t));
    }
    public List
getTeachers() {
        List
list = new ArrayList<>();
        list.add(new TeacherDto(1L, "老师1", 1L));
        list.add(new TeacherDto(2L, "老师2", 2L));
        list.add(new TeacherDto(3L, "老师3", 3L));
        list.add(new TeacherDto(4L, "老师4", 4L));
        return list;
    }
}
public class SubjectTransRepository implements TransRepository {
    @Override
    public Map
getTransValueMap(List
transValues, Annotation transAnno) {
        return getSubjects().stream()
            .filter(s -> transValues.contains(s.getId()))
            .collect(Collectors.toMap(SubjectDto::getId, s -> s));
    }
    public List
getSubjects() {
        List
list = new ArrayList<>();
        list.add(new SubjectDto(1L, "语文"));
        list.add(new SubjectDto(2L, "数学"));
        list.add(new SubjectDto(3L, "英语"));
        list.add(new SubjectDto(4L, "物理"));
        return list;
    }
}

Register repositories:

TransRepositoryFactory.register(new TeacherTransRepository());
TransRepositoryFactory.register(new SubjectTransRepository());
TransRepositoryFactory.register(new DictTransRepository(new DictLoader() {
    @Override
    public Map
loadDict(String dictGroup) {
        return dictMap().getOrDefault(dictGroup, new HashMap<>());
    }
    private Map
> dictMap() {
        Map
> map = new HashMap<>();
        map.put("sexDict", new HashMap<>());
        map.put("jobDict", new HashMap<>());
        map.get("sexDict").put("1", "男");
        map.get("sexDict").put("2", "女");
        map.get("jobDict").put("1", "学习委员");
        map.get("jobDict").put("2", "生活委员");
        map.get("jobDict").put("3", "宣传委员");
        map.get("jobDict").put("4", "班长");
        map.get("jobDict").put("5", "团支书");
        map.get("jobDict").put("6", "团长");
        return map;
    }
}));

Test the translation service with single objects and collections; the console output shows fields like sexName , jobName , teacherName , and subjectName populated correctly.

5. Advanced Features

5.1 Custom Annotations

By annotating a custom annotation with @Trans , you can reuse translation logic. Example:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
@Trans(using = TeacherTransRepository.class)
public @interface TeacherTrans {
    String trans() default "";
    String key() default "";
}

5.2 Value Extraction

Dictionary translation can use #val as the key to match the original field value.

5.3 Wrapper Class Translation

For wrapper objects like Result<T> , implement TransObjResolver to extract the actual data object for translation.

public class ResultResolver implements TransObjResolver {
    @Override
    public boolean support(Object obj) {
        return obj instanceof Result;
    }
    @Override
    public Object resolveTransObj(Object obj) {
        return ((Result
) obj).getData();
    }
}

Register the resolver with TransObjResolverFactory.register(new ResultResolver()); .

5.4 Spring Boot Integration

Add the starter dependency:

<dependency>
    <groupId>io.github.orangewest</groupId>
    <artifactId>easy-trans-spring-start</artifactId>
    <version>0.0.3</version>
</dependency>

Mark translation repositories with @Component and use @AutoTrans on controller methods to trigger automatic translation.

5.5 ORM Integration (MyBatis‑Plus example)

Define a @DbTrans annotation that specifies the target entity class, implement DbTransRepository using a TransDriver that queries the database by IDs, and plug it into the framework.

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
@Trans(using = DbTransRepository.class)
public @interface DbTrans {
    String trans();
    String key() default "";
    Class
entity() default BaseEntity.class;
}

The driver uses MyBatis SqlSession to fetch entities in batch.

6. Open‑Source Repository

https://gitee.com/orangewest/easy-trans

Author: 一只小闪闪 (Juejin post: https://juejin.cn/post/7361468008529412148 )

backendJavaSpringORMAnnotationframeworkData Translation
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.