如何用Gson序列化/反序列化含非字符串类型枚举的POJO
Got it, let's fix this to get the exact JSON structure you're aiming for. The problem with your current approach is that you're customizing how the ErrorCode enum is serialized, but Gson still wraps that result under the code field of your ApplicationError object. What you need is to flatten the enum's properties directly into the top-level JSON object alongside the description field.
Here's how to do it:
1. Implement Custom Serializer for ApplicationError
Instead of targeting the ErrorCode enum, create a serializer that handles the entire ApplicationError object. This lets you manually build the JSON structure exactly how you want it:
import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import java.lang.reflect.Type; import java.net.URL; public class ApplicationErrorSerializer implements JsonSerializer<ApplicationError> { @Override public JsonElement serialize(ApplicationError src, Type typeOfSrc, JsonSerializationContext context) { JsonObject jsonObject = new JsonObject(); // Add the error code value from the enum jsonObject.addProperty("code", src.getCode().getCode()); // Add the error message from the enum jsonObject.addProperty("message", src.getCode().getMessage()); // Add the description from ApplicationError jsonObject.addProperty("description", src.getDescription()); // Optional: Handle the infoURL field if it exists if (src.getInfoURL() != null) { jsonObject.addProperty("infoURL", src.getInfoURL().toString()); } return jsonObject; } }
2. Implement Corresponding Deserializer (for round-tripping)
If you need to deserialize the JSON back into an ApplicationError object, you'll also need a custom deserializer that maps the top-level fields back to your POJO and enum:
import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import java.lang.reflect.Type; import java.net.MalformedURLException; import java.net.URL; public class ApplicationErrorDeserializer implements JsonDeserializer<ApplicationError> { @Override public ApplicationError deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject jsonObject = json.getAsJsonObject(); // Find the matching ErrorCode using the top-level code value int errorCodeValue = jsonObject.get("code").getAsInt(); ErrorCode errorCode = null; for (ErrorCode code : ErrorCode.values()) { if (code.getCode() == errorCodeValue) { errorCode = code; break; } } if (errorCode == null) { throw new JsonParseException("Unknown error code: " + errorCodeValue); } // Extract description String description = jsonObject.get("description").getAsString(); // Optional: Handle infoURL if present URL infoURL = null; if (jsonObject.has("infoURL")) { try { infoURL = new URL(jsonObject.get("infoURL").getAsString()); } catch (MalformedURLException e) { throw new JsonParseException("Invalid infoURL format", e); } } // Build and return the ApplicationError object return new ApplicationError(errorCode, description, infoURL); } }
3. Register the Adapters with GsonBuilder
Now register both the serializer and deserializer when creating your Gson instance:
import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class Main { public static void main(String[] args) { ApplicationError applicationError = new ApplicationError( ErrorCode.INVALID_URL_PARAMETER, "Application identifier is missing" ); GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(ApplicationError.class, new ApplicationErrorSerializer()); gsonBuilder.registerTypeAdapter(ApplicationError.class, new ApplicationErrorDeserializer()); Gson gson = gsonBuilder.create(); // Serialize to JSON String jsonOutput = gson.toJson(applicationError); System.out.println(jsonOutput); // Output: {"code":20,"message":"Invalid URL parameter value","description":"Application identifier is missing"} // Deserialize back to object ApplicationError deserializedError = gson.fromJson(jsonOutput, ApplicationError.class); } }
Why Your Previous Approaches Didn't Work
- Edit 1 serialized
ErrorCodeas an array, but it was still nested under thecodefield ofApplicationError. - Edit 2 serialized
ErrorCodeas an object, again nested undercode.
By targeting the entire ApplicationError object instead of just the enum, we can flatten the enum's properties into the top-level JSON structure exactly as you requested.
内容的提问来源于stack exchange,提问作者Stéphane GRILLON

