Skip to content

Commit cbfa736

Browse files
committed
feat : 심플디티오 네이밍 수정 및 칼렌셕 기능 추가
1 parent a3b3115 commit cbfa736

File tree

3 files changed

+138
-75
lines changed

3 files changed

+138
-75
lines changed
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package com.querydsl.core.types;
2+
3+
import com.querydsl.core.types.dsl.EntityPathBase;
4+
import java.lang.reflect.Constructor;
5+
import java.lang.reflect.Field;
6+
import java.lang.reflect.Parameter;
7+
import java.util.ArrayList;
8+
import java.util.HashMap;
9+
import java.util.List;
10+
import java.util.Map;
11+
12+
public class NameBasedProjection<T> extends FactoryExpressionBase<T> {
13+
14+
private final List<Expression<?>> expressions;
15+
private final Constructor<? extends T> constructor;
16+
17+
@SafeVarargs
18+
public NameBasedProjection(Class<? extends T> type, EntityPathBase<?>... entities) {
19+
super(type);
20+
Map<String, Expression<?>> exprByName = collectExpressions(entities);
21+
this.constructor = findMatchingConstructor(type, exprByName);
22+
this.expressions = buildArgsForConstructor(this.constructor, exprByName);
23+
}
24+
25+
private Map<String, Expression<?>> collectExpressions(EntityPathBase<?>... entities) {
26+
Map<String, Expression<?>> map = new HashMap<>();
27+
for (EntityPathBase<?> entity : entities) {
28+
Class<?> clazz = entity.getClass();
29+
for (Field f : clazz.getFields()){
30+
String name = f.getName();
31+
if(!map.containsKey(name)){
32+
try{
33+
Object val = f.get(entity);
34+
if(val instanceof Expression){
35+
map.put(name, (Expression<?>) val);
36+
}
37+
}catch (IllegalAccessException e){
38+
39+
}
40+
}
41+
}
42+
}
43+
return map;
44+
}
45+
46+
47+
48+
private Constructor<? extends T> findMatchingConstructor(
49+
Class<? extends T> type,
50+
Map<String, Expression<?>> exprByName
51+
) {
52+
Constructor<?>[] ctors = type.getDeclaredConstructors();
53+
54+
for (Constructor<?> ctor : ctors) {
55+
Parameter[] params = ctor.getParameters();
56+
if (params.length == 0) continue;
57+
boolean allMatch = true;
58+
for (Parameter p : params) {
59+
String paramName = p.getName();
60+
if (!exprByName.containsKey(paramName)) {
61+
allMatch = false;
62+
break;
63+
}
64+
}
65+
if (allMatch) {
66+
ctor.setAccessible(true);
67+
return (Constructor<? extends T>) ctor;
68+
}
69+
}
70+
71+
Constructor<?> fallback = null;
72+
for (Constructor<?> ctor : ctors) {
73+
int paramCount = ctor.getParameterCount();
74+
if (paramCount > 0 && paramCount <= exprByName.size()) {
75+
if(fallback == null || ctor.getParameterCount() > fallback.getParameterCount()){
76+
fallback = ctor;
77+
}
78+
}
79+
}
80+
81+
if(fallback != null){
82+
fallback.setAccessible(true);
83+
return (Constructor<? extends T>) fallback;
84+
}
85+
86+
throw new RuntimeException("No constructor in " + type.getSimpleName()
87+
+ " can be satisfied by entities: " + exprByName.keySet());
88+
}
89+
90+
private List<Expression<?>> buildArgsForConstructor(
91+
Constructor<? extends T> ctor,
92+
Map<String, Expression<?>> exprByName
93+
) {
94+
List<Expression<?>> list = new ArrayList<>();
95+
96+
Parameter[] params = ctor.getParameters();
97+
98+
boolean unnamed = params.length > 0 && params[0].getName().startsWith("arg");
99+
Field[] fields = unnamed ? ctor.getDeclaringClass().getDeclaredFields() : new Field[0];
100+
101+
for (int i = 0; i < params.length; i++) {
102+
String name = unnamed ? fields[i].getName() : params[i].getName();
103+
Expression<?> expr = exprByName.get(name);
104+
if (expr == null) {
105+
throw new RuntimeException("No expression for parameter: " + name);
106+
}
107+
list.add(expr);
108+
}
109+
return list;
110+
}
111+
112+
@Override
113+
public T newInstance(Object... args) {
114+
try {
115+
return constructor.newInstance(args);
116+
} catch (Exception e) {
117+
throw new RuntimeException("Failed to create instance of " + getType().getSimpleName(), e);
118+
}
119+
}
120+
121+
@Override
122+
public List<Expression<?>> getArgs() {
123+
return expressions;
124+
}
125+
126+
@Override
127+
public <R, C> R accept(Visitor<R, C> v, C context) {
128+
return null;
129+
}
130+
131+
public static <T> NameBasedProjection<T> binder(
132+
Class<? extends T> type, EntityPathBase<?> entity) {
133+
return new NameBasedProjection<>(type, entity);
134+
}
135+
}

querydsl-libraries/querydsl-core/src/main/java/com/querydsl/core/types/SimpleDTOProjection.java

Lines changed: 0 additions & 72 deletions
This file was deleted.

querydsl-libraries/querydsl-core/src/test/java/com/querydsl/core/SimpleDTOProjectionTest.java renamed to querydsl-libraries/querydsl-core/src/test/java/com/querydsl/core/NameBasedProjectionTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44

55
import com.querydsl.core.domain.QAnimal;
66
import com.querydsl.core.types.Projections;
7-
import com.querydsl.core.types.SimpleDTOProjection;
7+
import com.querydsl.core.types.NameBasedProjection;
88
import java.sql.Date;
99
import org.junit.Test;
1010

11-
public class SimpleDTOProjectionTest {
11+
public class NameBasedProjectionTest {
1212

1313
public static class AnimalDTO {
1414
private boolean alive;
@@ -128,7 +128,7 @@ public void testSimpleDTOProjectionWithFields() {
128128

129129
// Create DTO using SimpleDTOProjection.fields()
130130
AnimalDTO dtoFromSimpleDTOProjection =
131-
SimpleDTOProjection.fields(AnimalDTO.class, animal)
131+
NameBasedProjection.binder(AnimalDTO.class, animal)
132132
.newInstance(
133133
true, // alive
134134
65.5, // bodyWeight

0 commit comments

Comments
 (0)