• μλ νμΈμ~ μ΄μ μ μ΄μνλ λΈλ‘κ·Έ λ° GitHub, κ³΅λΆ λ΄μ©μ μ 리νλ Study-GitHub κ° μμ΅λλ€!
• π
β BeanUtils.copyProperties()
μλ νμΈμ, μ΄λ²μ μ 리ν λ΄μ©μ Springμ BeanUtils ν΄λμ€μ copyProperties λ©μλ μ λλ€.
μ΅κ·Ό μ€νλ§μ 곡λΆνλ©° Entityμ Dto μ¬μ΄μμ κ°μ 볡μ¬ν λ μ΄ λ©μλλ₯Ό μ¬μ©νλκ±Έ λ΄€μλλ°μ,
λ°λΌμ μ 리ν΄λ³΄κ³ μ μμ±νκ² λμμ΅λλ€.
public UserDto(User source) {
copyProperties(source, this);
this.profileImageUrl = source.getProfileImageUrl().orElse(null);
this.lastLoginAt = source.getLastLoginAt().orElse(null);
}
copyProperties λ©μλλ μλ³Έ κ°μ²΄λ₯Ό 볡μ¬ν λ μ¬μ©νλ λ©μλμΈλ°μ,
λ§μ½ κΈ°μ‘΄μ κ°μ²΄λ₯Ό 볡μ¬ν κ°μ²΄κ° νμνλ° Setter λ©μλλ‘ κ°μ μ€μ νλ€λ©΄...?
νλμ κ°―μκ° μ μΌλ©΄ μκ΄μκ² μ§λ§, λ§μμ§λ©΄ μ½λλ λ°©λν΄μ§κ³ λ²κ±°λ‘μμ§λλ°μ..
μ΄λ copyProperties λ©μλλ₯Ό ν΅ν΄ νΈνκ² λ³΅μ¬λ₯Ό ν μ μμ΅λλ€. π
μ νν μλ£λ 곡μλ¬Έμ μμ νμΈνμλ©΄ λ©λλ€!
β copyProperties() λ©μλ
μ μ½λμ μλ BeanUtils ν΄λμ€λ Spring Frameworkμ 5.2.10 λ²μ μ΄κ³ μ΅μ λ²μ μ 5.3.4 μΈλ°μ,
μ΅μ λ²μ μμλ λ©μλκ° 3κ°μΈλ° μ μ½λμλ λ©μλκ° 4κ°κ° μ€λ²λ‘λ© λμ΄μμ΅λλ€.
BeanUtils ν΄λμ€μ copyProperties λ©μλλ μμ κ°μ΄ μΈ κ°μ λ©μλκ° μμ΅λλ€.
* Spring Framework 5.3.4 API μ λλ€.
λ νλΌλ―Έν°λ λ€μκ³Ό κ°μ νΉμ§μ κ°μ§λλ€.
• 첫 λ²μ§Έ μΈμμΈ source μλ getter λ©μλκ° μ‘΄μ¬ν΄μΌ ν©λλ€.
• λ λ²μ§Έ μΈμμΈ target μλ setter λ©μλκ° μ‘΄μ¬ν΄μΌ ν©λλ€.
λ©μλμ κ°―μλ ν¬κ² μ€μνμ§ μμ κ² κ°κ³ , λ€μ λ λ©μλμ λν΄ μμΈν 보면 μ’μ κ² κ°μ΅λλ€. π
public static void copyProperties(Object source, Object target) throws BeansException {
copyProperties(source, target, (Class)null, (String[])null);
}
public static void copyProperties(Object source, Object target, String... ignoreProperties) throws BeansException {
copyProperties(source, target, (Class)null, ignoreProperties);
}
sourceλ μλ³Έ κ°μ²΄, targetλ 볡μ¬ν κ°μ²΄μ λλ€.
ignorePropertiesλ κ°λ³ μΈμλ‘ νλΌλ―Έν°λ₯Ό λ°κ³ μλλ°μ, μ΄λ κ°μ²΄λ₯Ό 볡μ¬ν λ μ€μ μ μ μΈν μ μμ΅λλ€.
μ΄μ μμ λ₯Ό ν΅ν΄ μ΄ν΄λ³΄κ² μ΅λλ€!
package com.github.prgrms.social.util;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
public class BeanUtil {
static class Source {
private String name;
private int age;
private String email;
public Source(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("name", name)
.append("age", age)
.append("email", email)
.toString();
}
}
static class Target {
private String name;
private int age;
private String email;
public Target(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("name", name)
.append("age", age)
.append("email", email)
.toString();
}
}
public static void main(String[] args) {
Source source = new Source("JuHyun", 20, "a@a.com");
Target target = new Target("JuBal", 30, "b@b.com");
target.setName(source.getName());
target.setAge(source.getAge());
target.setEmail(source.getEmail());
System.out.println(source.toString());
System.out.println("===================");
System.out.println(target.toString());
}
}
Sourceμ Target ν΄λμ€μλ name, age, emailμ μμ±μ΄ μκ³ getter, setter, toString λ©μλκ° μ‘΄μ¬ν©λλ€.
(μ¬μ€ μμμ λ§μλλ¦°λλ‘, Source ν΄λμ€μλ getter λ©μλλ§, Target ν΄λμ€μλ setter λ©μλλ§ μ‘΄μ¬ν΄λ μ μμ μΌλ‘ μλν©λλ€ π)
κΈ°μ‘΄μ Source κ°μ²΄λ₯Ό Target κ°μ²΄μ 볡μ¬νκΈ° μν΄ setter λ©μλλ‘ λͺ¨λ κ°μ μ§μ ν΄μ£Όλλ°μ,
target.setName(source.getName());
target.setAge(source.getAge());
target.setEmail(source.getEmail());
μμ κ²½μ° νλκ° λͺ κ° μκΈ°μ λ¬Έμ κ° λμ§λ μμ§λ§, μ΄λ¬ν νλκ° λ§μμ§μλ‘ μ½λκ° λ°©λν΄μ§ μ μμ΅λλ€.
λ°λΌμ μ μ½λλ₯Ό BeanUtils ν΄λμ€μ copyProperties λ©μλλ₯Ό μ¬μ©νλ©΄ κ°λ΅νκ² κ°μ²΄λ₯Ό 볡μ¬ν μ μμ΅λλ€.
public static void main(String[] args) {
Source source = new Source("JuHyun", 20, "a@a.com");
Target target = new Target("JuBal", 30, "b@b.com");
BeanUtils.copyProperties(source, target);
System.out.println(source.toString());
System.out.println("=================================================");
System.out.println(target.toString());
}
μλ Sourceμ λͺ¨λ μμ±μ 볡μ¬νλ νΉμ§μ΄ μλλ°μ,
λ§μ½ λλ λͺ¨λ μμ±μ΄ μλ νΉμ μμ±λ§ 볡μ¬νκ³ μ νλ€..
ν λ μ¬μ©νλ κ²μ΄ ignoreProperties νλΌλ―Έν° μ λλ€.
public static void main(String[] args) {
Source source = new Source("JuHyun", 20, "a@a.com");
Target target = new Target("JuBal", 30, "b@b.com");
BeanUtils.copyProperties(source, target, "age", "email");
System.out.println(source.toString());
System.out.println("=================================================");
System.out.println(target.toString());
}
μ κ²°κ³Όλ₯Ό 보μλ©΄ age μ emailμ 무μνλλ‘ μ€μ νμΌλ―λ‘, μ€μ μ μΌλ‘λ name κ°λ§ 볡μ¬κ° λ©λλ€.
β λλ²κΉ
μ€μ 볡μ¬λλ copyProperties λ©μλμ μ½λλ μλμ κ°μ΅λλ€.
private static void copyProperties(Object source, Object target, @Nullable Class<?> editable, @Nullable String... ignoreProperties) throws BeansException {
Assert.notNull(source, "Source must not be null");
Assert.notNull(target, "Target must not be null");
Class<?> actualEditable = target.getClass();
if (editable != null) {
if (!editable.isInstance(target)) {
throw new IllegalArgumentException("Target class [" + target.getClass().getName() + "] not assignable to Editable class [" + editable.getName() + "]");
}
actualEditable = editable;
}
PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
List<String> ignoreList = ignoreProperties != null ? Arrays.asList(ignoreProperties) : null;
PropertyDescriptor[] var7 = targetPds;
int var8 = targetPds.length;
for(int var9 = 0; var9 < var8; ++var9) {
PropertyDescriptor targetPd = var7[var9];
Method writeMethod = targetPd.getWriteMethod();
if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
if (sourcePd != null) {
Method readMethod = sourcePd.getReadMethod();
if (readMethod != null && ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
try {
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
}
Object value = readMethod.invoke(source);
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
}
writeMethod.invoke(target, value);
} catch (Throwable var15) {
throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", var15);
}
}
}
}
}
}
μ½λκ° μ’ λ³΅μ‘νλ°μ, μ΄λ»κ² λμνλμ§ κΆκΈν΄μ λλ²κΉ μ ν΅ν΄ κ°λ΅νκ²! μ΄ν΄λ³΄μμ΅λλ€.
(μλͺ»λ λΆλΆμ΄ μμΌλ©΄ λ§μν΄μ£Όμλ©΄ κ°μ¬νκ² μ΅λλ€π€)
μμ λ μ§μ μ ν¬μΈνΈλ₯Ό κ±Έκ³ λλ²κΉ μ μ€νν΄ λ³΄μμ΅λλ€.
1) editable 체ν¬
Assert.notNull(source, "Source must not be null");
Assert.notNull(target, "Target must not be null");
Class<?> actualEditable = target.getClass();
if (editable != null) {
if (!editable.isInstance(target)) {
throw new IllegalArgumentException("Target class [" + target.getClass().getName() + "] not assignable to Editable class [" + editable.getName() + "]");
}
actualEditable = editable;
}
λ¨Όμ editableμ nullμ΄λ―λ‘ μ λ¬Έμ₯μ νμκ° μμ΅λλ€.
2) λ°°μ΄μ κΈΈμ΄(νλ) λ° ignoreList(μμ± λ¬΄μν νλ) μ§μ
PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
List<String> ignoreList = ignoreProperties != null ? Arrays.asList(ignoreProperties) : null;
PropertyDescriptor[] var7 = targetPds;
int var8 = targetPds.length;
μμ κ°μ΄ targetPds λ°°μ΄μ κΈΈμ΄κ° λνλλλ°μ,
μ actualEditableμ target.getClass() μμμ Class μ λλ€.
λ°°μ΄μ κΈΈμ΄λ νλ κ°―μμ classλ₯Ό ν©μΉ 4 κ° λ©λλ€.
λν ignoreListμ μ€μ μ 무μν propertyλ€μ΄ μ§μ μ΄ λλλ°μ,
νμ¬ ageμ emailμ μ§μ νμΌλ―λ‘, μ ignoreListμλ "age" μ "email" μ κ°μ΄ μ μ₯μ΄ λ©λλ€.
3) forλ¬Έ - μ€μ νλ 볡μ¬
for(int var9 = 0; var9 < var8; ++var9) {
PropertyDescriptor targetPd = var7[var9];
Method writeMethod = targetPd.getWriteMethod();
if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
if (sourcePd != null) {
Method readMethod = sourcePd.getReadMethod();
if (readMethod != null) {
ResolvableType sourceResolvableType = ResolvableType.forMethodReturnType(readMethod);
ResolvableType targetResolvableType = ResolvableType.forMethodParameter(writeMethod, 0);
if (targetResolvableType.isAssignableFrom(sourceResolvableType)) {
try {
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
}
Object value = readMethod.invoke(source);
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
}
writeMethod.invoke(target, value);
} catch (Throwable var17) {
throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", var17);
}
}
}
}
}
}
λ§μ§λ§μΌλ‘ forλ¬Έ μ λλ€.
μμμλ PropertyDescriptor λ°°μ΄μ μννλ©° ignoreListμ ν¬ν¨λ(μ€μ μ μΈ) νλμΌ κ²½μ°, ifλ¬Έμ 건λλ°κ³ ,
ignoreListμ ν¬ν¨λμ§ μμ(κ° λ³΅μ¬) νλμΌ κ²½μ°, ifλ¬Έμ ν΅ν΄ μ€μ κ°μ 볡μ¬νλ μ½λμ λλ€.
μμ κ°μ΄ age, emailμ κ²½μ° λͺ¨λ 건λλ°μ§λ§
nameμ κ²½μ° ifλ¬Έ λ΄λΆλ‘ λ€μ΄κ°μ κ°μ 볡μ¬ν©λλ€.
μ€μ Target ν΄λμ€μ setterλ₯Ό μ¬μ©νκΈ° λλ¬Έμ 볡μ¬ν κ°μ²΄μλ setter λ©μλκ° νμν©λλ€.
μ€μ Source ν΄λμ€μ getterλ₯Ό μ¬μ©νκΈ° λλ¬Έμ κΈ°μ‘΄ κ°μ²΄λ getter λ©μλκ° νμν©λλ€.
μ€μ κ°μ 볡μ¬νλ λΆλΆμ λλ€.
writeMethodμ invokeλ₯Ό ν΅ν΄ target(볡μ¬ν κ°μ²΄)μ value(name="JuHyun") μ κ°μ μ€μ ν©λλ€.
μ writeMethod.invoke(target, value) μ λ΄λΆλ‘ λ€μ΄κ°λ©΄ μμ κ°μ΄ setter λ©μλκ° μ€νμ΄ λ©λλ€.
리νλ μ μ ν΅ν΄ μλνλ―λ‘, value κ°μ targetμ κ°μ μ€μ νλ κ±Έ λ³Ό μ μμ΅λλ€.
'Spring' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
Spring Boot Maven profile μ΄μ & κ°λ° DB λΆλ¦¬(AWS EC2) (6) | 2021.06.18 |
---|---|
JUnit - @ParameterizedTest, @ValueSource, @CsvSource, @MethodSource μ΄λ Έν μ΄μ (4) | 2021.06.08 |
[Spring] Maven λ©ν°λͺ¨λ νλ‘μ νΈ (0) | 2021.02.09 |
[Spring] - @ModelAttribute, @RequestParam (0) | 2021.02.02 |
[Spring] HandlerMethodArgumentResolver (0) | 2021.01.30 |
λκΈ