JsonSerializerDemo.java
package jsonserializer;
import models.Actor;
import models.Movie;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
public class JsonSerializerDemo {
public static void main(String[] args) throws IllegalAccessException {
Actor actor1 = new Actor("Chris Hemsworth", new String[]{"Thor", "Extraction"});
Actor actor2 = new Actor("Scarlett Johansson", new String[]{"Avengers", "Lucy"});
Actor actor3 = new Actor("Robert Downey Jr.", new String[]{"Iron Man", "Sherlock Holmes"});
Movie movie = new Movie("Avengers: Endgame", 8.4f, new String[]{"Action", "Sci-Fi", "Adventure"},
new Actor[]{actor1, actor2, actor3});
String jsonOutput = serializeToJson(movie, 0);
System.out.println(jsonOutput);
}
public static String serializeToJson(Object obj, int indentLevel) throws IllegalAccessException {
Field[] fields = obj.getClass().getDeclaredFields();
StringBuilder jsonBuilder = new StringBuilder();
jsonBuilder.append(addIndentation(indentLevel)).append("{").append("\n");
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
field.setAccessible(true);
if (field.isSynthetic()) {
continue;
}
jsonBuilder.append(addIndentation(indentLevel + 1))
.append(formatString(field.getName()))
.append(": ");
if (field.getType().isPrimitive()) {
jsonBuilder.append(formatPrimitiveValue(field.get(obj), field.getType()));
} else if (field.getType().equals(String.class)) {
jsonBuilder.append(formatString((String) field.get(obj)));
} else if (field.getType().isArray()) {
jsonBuilder.append(convertArrayToJson(field.get(obj), indentLevel + 1));
} else {
jsonBuilder.append(serializeToJson(field.get(obj), indentLevel + 1));
}
if (i < fields.length - 1) {
jsonBuilder.append(",");
}
jsonBuilder.append("\n");
}
jsonBuilder.append(addIndentation(indentLevel)).append("}");
return jsonBuilder.toString();
}
private static String convertArrayToJson(Object arrayObj, int indentLevel) throws IllegalAccessException {
StringBuilder jsonBuilder = new StringBuilder();
int length = Array.getLength(arrayObj);
Class<?> componentType = arrayObj.getClass().getComponentType();
jsonBuilder.append("[\n");
for (int i = 0; i < length; i++) {
Object element = Array.get(arrayObj, i);
if (componentType.isPrimitive()) {
jsonBuilder.append(addIndentation(indentLevel + 1))
.append(formatPrimitiveValue(element, componentType));
} else if (componentType.equals(String.class)) {
jsonBuilder.append(addIndentation(indentLevel + 1))
.append(formatString((String) element));
} else {
jsonBuilder.append(serializeToJson(element, indentLevel + 1));
}
if (i < length - 1) {
jsonBuilder.append(",");
}
jsonBuilder.append("\n");
}
jsonBuilder.append(addIndentation(indentLevel)).append("]");
return jsonBuilder.toString();
}
private static String addIndentation(int level) {
return "\t".repeat(level);
}
private static String formatPrimitiveValue(Object value, Class<?> type) {
if (type.equals(boolean.class) || type.equals(int.class) || type.equals(short.class)) {
return value.toString();
} else if (type.equals(float.class) || type.equals(double.class)) {
return String.format("%.2f", value);
}
throw new UnsupportedOperationException("Unsupported data type: " + type.getName());
}
private static String formatString(String value) {
return "\"" + value + "\"";
}
}
models/Actor.java
package models;
public class Actor {
private final String name;
private final String[] notableMovies;
public Actor(String name, String[] notableMovies) {
this.name = name;
this.notableMovies = notableMovies;
}
}
models/Movie.java
package models;
public class Movie {
private final String title;
private final float imdbRating;
private final String[] genres;
private final Actor[] cast;
public Movie(String title, float imdbRating, String[] genres, Actor[] cast) {
this.title = title;
this.imdbRating = imdbRating;
this.genres = genres;
this.cast = cast;
}
}
1. Array.getLength(Object array)
- 설명: 배열 객체의 길이를 반환합니다.
- 사용 예:
int length = Array.getLength(arrayObj);
2. Array.get(Object array, int index)
- 설명: 배열의 특정 인덱스에 있는 요소를 가져옵니다.
- 사용 예:
Object element = Array.get(arrayObj, i);
3. Class.isArray()
- 설명: 특정 클래스 객체가 배열인지 확인합니다.
- 사용 예:
if (field.getType().isArray()) { jsonBuilder.append(convertArrayToJson(field.get(obj), indentLevel + 1)); }
4. Class.getComponentType()
- 설명: 배열의 요소 타입(컴포넌트 타입)을 반환합니다.
- 사용 예:
Class<?> componentType = arrayObj.getClass().getComponentType();
5. Class.getDeclaredFields() 및 Field.setAccessible(true)
- 설명: 이전 예제와 동일하게 객체의 필드를 가져오고 접근 제한을 해제하여 값을 읽습니다.
- 사용 예:
Field[] fields = obj.getClass().getDeclaredFields(); field.setAccessible(true);
예제 코드 분석
1. 배열 처리 로직 (convertArrayToJson)
- 배열 직렬화를 위해 Array.getLength와 Array.get을 사용합니다.
- 요소 타입에 따라 분기:
- 기본형(Primitive): formatPrimitiveValue를 호출.
- 문자열(String): JSON 문자열로 포맷팅.
- 복합 객체(Object): 재귀적으로 serializeToJson 호출.
int length = Array.getLength(arrayObj);
for (int i = 0; i < length; i++) {
Object element = Array.get(arrayObj, i);
if (componentType.isPrimitive()) {
jsonBuilder.append(formatPrimitiveValue(element, componentType));
} else if (componentType.equals(String.class)) {
jsonBuilder.append(formatString((String) element));
} else {
jsonBuilder.append(serializeToJson(element, indentLevel + 1));
}
}
2. JSON 직렬화 과정
- 필드 접근 및 데이터 타입 확인:
- 배열인 경우, 배열 처리 메서드 convertArrayToJson으로 위임.
if (field.getType().isArray()) { jsonBuilder.append(convertArrayToJson(field.get(obj), indentLevel + 1)); }
- 배열인 경우, 배열 처리 메서드 convertArrayToJson으로 위임.
- 출력 예: Movie 객체를 직렬화하면 다음 JSON 결과가 생성됩니다:
{
"title": "Avengers: Endgame",
"imdbRating": 8.40,
"genres": [
"Action",
"Sci-Fi",
"Adventure"
],
"cast": [
{
"name": "Chris Hemsworth",
"notableMovies": [
"Thor",
"Extraction"
]
},
{
"name": "Scarlett Johansson",
"notableMovies": [
"Avengers",
"Lucy"
]
},
{
"name": "Robert Downey Jr.",
"notableMovies": [
"Iron Man",
"Sherlock Holmes"
]
}
]
}
'(2024-10) 스파르타 내일배움캠프 - 백엔드 > Java Reflect' 카테고리의 다른 글
Getter 동적 생성 (0) | 2024.11.27 |
---|---|
ConfigLoader 예제 (0) | 2024.11.27 |
Field 제어 (0) | 2024.11.27 |
Java Reflect의 Array 제어 (0) | 2024.11.27 |
Constructor 예제, 싱글턴에서(2) (0) | 2024.11.26 |