'enforce enum serialization with a spring jpa projection?

Say I have the following JPA entity, with an enum field ON/OFF mapped to an SQL enum("on", "off").

@Entity
public class Process {
    @Id
    private Long Id;
    @Convert(converter = StatusConverter.class)
    private Status status;

    // getter/setter omitted
}

public enum Status {
    ON("on"),
    OFF("off");

    private final String status;

    Status(String status) {
        this.status = status;
    }

    // JSON (de)serialization
    @JsonCreator
    public static Status decode(String status) {
        return valueOf(status.toUpperCase());
    }

    @JsonValue
    public getStatus() {
        return status;
    }

    // DAO layer conversion
    public String toDatabaseColumn() {
        return this.name().toLowerCase();
    }
}

@Converter
public class StatusConverter implements AttributeConverter<Status, String> {
    @Override
    public String convertToDatabaseColumn(Status attribute) {
        return attribute.toDatabaseColumn();
    }

    @Override
    public Status convertToEntityAttribute(String dbData) {
        return Status.decode(dbData);
    }
}

// Spring JPA projection
public interface ProcessSummary {
    String getStatus();
}

// a minimalist JPA repository
public interface ProcessRepository extends Repository<Process, Long> {
    <T> T findById(Long id, Class<T> type;
}

If I use repository.findById(1L, Process.class) in a REST controller, both the DAO layer conversion and the JSON serialization work as expected :

  • my database record has its status set to on
  • it is mapped to the Java Status.ON
  • the entity is serialized as
    {
        "status" : "on" 
    }

But if I use repository.findById(1L, ProcessSummary.class) instead, the entity is serialized as

    {
        "status" : "ON" 
    }

How can I get the same result when using a projection as target type? Is it possible with a projection, or should I try something else (a DTO class maybe)?



Solution 1:[1]

Sorry folks, it was just me and a textbook case of of PEBKAC :)

The getStatus() method in the interface MUST return a Status, not a String.

public interface ProcessSummary {
    String getStatus();
}

does what it's asked: converts the enum to a String, hence Status.ON is serialized as "ON", while

public interface ProcessSummary {
    Status getStatus();
}

indeed uses the @JsonValue annotated method and serializes Status.ON as "on".

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Marc Tarin