The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.
Follows the import procedure in README.md.
source/ the originating repository verbatim — 78 documents, 28 SVGs,
8 manifests, plus .source-revision recording the commit
final/ the SSOT
document.md 729 lines written from the 29 experiment documents, not
concatenated: what was predicted, what was measured, and
where the measurement itself was wrong
evidence/raw 125 outputs, flattened to <experiment>__<file> because
the originals collided (01-baseline.txt appeared three
times) and the audit only globs the top level
evidence/meta one per raw file; command and exitCode are null and the
README says why rather than inventing them
evidence/browser 22 captures
assets/ three diagrams through techviz
.techviz/ their VizSpecs
A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.
Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.
verify-pipeline.py passes. audit-records.py reports no issues.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
182 lines
22 KiB
XML
182 lines
22 KiB
XML
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="2394" viewBox="0 0 1200 2394" role="img">
|
|
<title>terminal evidence</title>
|
|
<desc>Terminal-style rendering generated from retained command output. Sensitive-looking values are redacted in the visual asset.</desc>
|
|
<rect x="1" y="1" width="1198" height="2392" rx="14" fill="#0d1117" stroke="#30363d"/>
|
|
<rect x="1" y="1" width="1198" height="44" rx="14" fill="#161b22"/>
|
|
<rect x="1" y="30" width="1198" height="14" fill="#161b22"/>
|
|
<circle cx="24" cy="22" r="6" fill="#ff5f57"/>
|
|
<circle cx="44" cy="22" r="6" fill="#febc2e"/>
|
|
<circle cx="64" cy="22" r="6" fill="#28c840"/>
|
|
<text x="92" y="27" fill="#8b949e" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace">terminal evidence</text>
|
|
<text x="24" y="68" fill="#c9d1d9" font-size="15" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">$ mkdir -p /tmp/probe
|
|
|
|
echo '# 락파일이 고정한 좌표에서 클래스패스를 만든다. Gradle 실행 없이 재현된다.'
|
|
cat > /tmp/prob</tspan><tspan x="24" dy="22">e/cp.sh <<'CPSH'
|
|
# 락파일이 고정한 좌표에서 jar 경로를 만든다. Gradle 실행 없이 재현된다.
|
|
CACHE=$(ls -d "$HOME"/.gradle/</tspan><tspan x="24" dy="22">caches/modules-2/files-2.1 2>/dev/null || echo /root/.gradle/caches/modules-2/files-2.1)
|
|
jars=""
|
|
for coord in \
|
|
org.sp</tspan><tspan x="24" dy="22">ringframework.data:spring-data-jpa \
|
|
org.springframework.data:spring-data-commons \
|
|
com.querydsl:querydsl-core \
|
|
c</tspan><tspan x="24" dy="22">om.querydsl:querydsl-jpa \
|
|
org.springframework:spring-core \
|
|
org.springframework:spring-tx \
|
|
jakarta.persistence:j</tspan><tspan x="24" dy="22">akarta.persistence-api \
|
|
org.slf4j:slf4j-api ; do
|
|
group=${coord%%:*}; name=${coord##*:}
|
|
ver=$(grep -m1 "^$group:$n</tspan><tspan x="24" dy="22">ame:" adapter/outbound/persistence-jpa/gradle.lockfile | cut -d: -f3 | cut -d= -f1)
|
|
jar=$(find "$CACHE/$group/$name/$v</tspan><tspan x="24" dy="22">er" -name "$name-$ver*.jar" ! -name '*sources*' ! -name '*javadoc*' 2>/dev/null | head -1)
|
|
echo "$name $ver -> ${jar:-</tspan><tspan x="24" dy="22">MISSING}" >&2
|
|
jars="$jars:$jar"
|
|
done
|
|
echo "adapter/outbound/persistence-jpa/build/classes/java/main$jars"
|
|
CPSH
|
|
CP=$(ba</tspan><tspan x="24" dy="22">sh /tmp/probe/cp.sh 2>/tmp/probe/cp.log)
|
|
sed 's|/root/.gradle/caches/modules-2/files-2.1/|<cache>/|; s|/[0-9a-f]\{40\}/|</tspan><tspan x="24" dy="22">/|' /tmp/probe/cp.log
|
|
echo -n '# app-bootstrap 의 락파일에 querydsl 이 있는가: '
|
|
grep -c querydsl app-bootstrap/gradle</tspan><tspan x="24" dy="22">.lockfile || true
|
|
|
|
echo
|
|
echo '# 제한 없음 명세 팩토리가 어느 람다에 링크되는가'
|
|
javap -p -v -cp "$CP" org.springframewor</tspan><tspan x="24" dy="22">k.data.jpa.domain.Specification 2>/dev/null \
|
|
| awk '/^BootstrapMethods:/,0' | sed -n '1,6p' | cut -c1-110
|
|
echo '# </tspan><tspan x="24" dy="22">그 람다의 본문'
|
|
javap -p -c -cp "$CP" org.springframework.data.jpa.domain.Specification 2>/dev/null \
|
|
| awk '/Predicat</tspan><tspan x="24" dy="22">e lambda\$0\(/{c=4} c-->0'
|
|
|
|
echo
|
|
echo '# 그 명세와 자바 널을 두 검사에 각각 넣는다'
|
|
cat > /tmp/probe/SpecProbe.java <<'J</tspan><tspan x="24" dy="22">AVA'
|
|
import dev.caskeleton.adapter.outbound.persistence.springdata.SpecificationPolicy;
|
|
import org.springframework.data.</tspan><tspan x="24" dy="22">domain.PageRequest;
|
|
import org.springframework.data.domain.Pageable;
|
|
import org.springframework.data.jpa.domain.Specific</tspan><tspan x="24" dy="22">ation;
|
|
|
|
/** 라이브러리가 공식으로 주는 제한 없음 명세를 정책에 넘긴다. */
|
|
public class SpecProbe {
|
|
public static void </tspan><tspan x="24" dy="22">main(String[] args) {
|
|
Pageable paged = PageRequest.of(0, 50);
|
|
Specification<Object> unrestricted = Specification</tspan><tspan x="24" dy="22">.unrestricted();
|
|
|
|
System.out.println("Specification.unrestricted() 가 널인가 : " + (unrestricted == null));
|
|
Syst</tspan><tspan x="24" dy="22">em.out.println("그 명세의 toPredicate 가 돌려주는 값 : " + unrestricted.toPredicate(null, null, null));
|
|
|
|
System.ou</tspan><tspan x="24" dy="22">t.println("requireBounded(토큰 없이) : " + verdict(() -> SpecificationPolicy.requireBounded(unrestricted, paged, null))</tspan><tspan x="24" dy="22">);
|
|
System.out.println("requirePredicate : " + verdict(() -> SpecificationPolicy.requirePredicate(unrestric</tspan><tspan x="24" dy="22">ted)));
|
|
System.out.println("requireBounded(널 명세) : " + verdict(() -> SpecificationPolicy.requireBounded(null, </tspan><tspan x="24" dy="22">paged, null)));
|
|
System.out.println("requirePredicate(널 명세) : " + verdict(() -> SpecificationPolicy.requirePredic</tspan><tspan x="24" dy="22">ate(null)));
|
|
}
|
|
|
|
private static String verdict(Runnable call) {
|
|
try {
|
|
call.run();
|
|
return "통과";
|
|
</tspan><tspan x="24" dy="22">} catch (RuntimeException refused) {
|
|
return "거절 — " + refused.getMessage();
|
|
}
|
|
}
|
|
}
|
|
JAVA
|
|
javac -encoding UT</tspan><tspan x="24" dy="22">F-8 -cp "$CP" -d /tmp/probe /tmp/probe/SpecProbe.java \
|
|
&& java -Dstdout.encoding=UTF-8 -cp "$CP:/tmp/probe" SpecProbe</tspan><tspan x="24" dy="22">
|
|
|
|
echo
|
|
echo '# 페이지 경계 검사는 그대로 남아 있다'
|
|
S=adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adap</tspan><tspan x="24" dy="22">ter/outbound/persistence/springdata/SpecificationPolicy.java
|
|
grep -n -A3 'pageable.isUnpaged()' "$S"
|
|
echo '# 반면 requ</tspan><tspan x="24" dy="22">irePredicate 는 Pageable 을 받지 않는다'
|
|
grep -n 'public static void requirePredicate' "$S"
|
|
|
|
echo
|
|
echo '# 형제 정책에 Qu</tspan><tspan x="24" dy="22">erydsl 쪽 대응물을 넣는다'
|
|
cat > /tmp/probe/SiblingProbe.java <<'JAVA'
|
|
import com.querydsl.core.BooleanBuilder;
|
|
import d</tspan><tspan x="24" dy="22">ev.caskeleton.adapter.outbound.persistence.querydsl.PredicatePolicy;
|
|
import dev.caskeleton.adapter.outbound.persistence.</tspan><tspan x="24" dy="22">querydsl.QueryPage;
|
|
|
|
public class SiblingProbe {
|
|
public static void main(String[] args) {
|
|
QueryPage page = QueryPa</tspan><tspan x="24" dy="22">ge.of(0, 50);
|
|
BooleanBuilder empty = new BooleanBuilder();
|
|
System.out.println("빈 BooleanBuilder 가 널인가 : " +</tspan><tspan x="24" dy="22"> (empty == null));
|
|
System.out.println("hasValue : " + empty.hasValue());
|
|
try {
|
|
Predicat</tspan><tspan x="24" dy="22">ePolicy.requireBounded(empty, page);
|
|
System.out.println("PredicatePolicy 판정 : 통과");
|
|
} catch (Runtim</tspan><tspan x="24" dy="22">eException refused) {
|
|
System.out.println("PredicatePolicy 판정 : 거절 — " + refused.getMessage());
|
|
}
|
|
</tspan><tspan x="24" dy="22"> }
|
|
}
|
|
JAVA
|
|
javac -encoding UTF-8 -cp "$CP" -d /tmp/probe /tmp/probe/SiblingProbe.java \
|
|
&& java -Dstdout.encoding=UTF-8</tspan><tspan x="24" dy="22"> -cp "$CP:/tmp/probe" SiblingProbe
|
|
|
|
echo
|
|
echo '# 형제 쪽 진입점은 항상 limit 을 붙이고, 그 리프에서 Querydsl 은 compileO</tspan><tspan x="24" dy="22">nly 다'
|
|
Q=adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/querydsl/QuerydslJp</tspan><tspan x="24" dy="22">aSupport.java
|
|
sed -n '44,49p' "$Q"
|
|
grep -n 'compileOnly.*querydsl' adapter/outbound/persistence-jpa/build.gradle
|
|
sed -n </tspan><tspan x="24" dy="22">'13,15p' "$Q"</tspan></text>
|
|
<text x="24" y="1014" fill="#8b949e" font-size="13" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">cwd: /shared/codebase/clean-architecture-backend-template/src</tspan></text>
|
|
<text x="24" y="1036" fill="#8b949e" font-size="13" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">time: 2026-09-02T03:59:23+00:00 · exit 0</tspan></text>
|
|
<line x1="24" y1="1050" x2="1176" y2="1050" stroke="#30363d"/>
|
|
<text x="24" y="1090" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 락파일이 고정한 좌표에서 클래스패스를 만든다. Gradle 실행 없이 재현된다.</tspan></text>
|
|
<text x="24" y="1112" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">spring-data-jpa 4.0.7 -> <cache>/org.springframework.data/spring-data-jpa/4.0.7/spring-data-jpa-4.0.7.jar</tspan></text>
|
|
<text x="24" y="1134" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">spring-data-commons 4.0.7 -> <cache>/org.springframework.data/spring-data-commons/4.0.7/spring-data-commons-4.0.7.jar</tspan></text>
|
|
<text x="24" y="1156" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">querydsl-core 5.1.0 -> <cache>/com.querydsl/querydsl-core/5.1.0/querydsl-core-5.1.0.jar</tspan></text>
|
|
<text x="24" y="1178" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">querydsl-jpa 5.1.0 -> <cache>/com.querydsl/querydsl-jpa/5.1.0/querydsl-jpa-5.1.0-jakarta.jar</tspan></text>
|
|
<text x="24" y="1200" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">spring-core 7.0.9 -> <cache>/org.springframework/spring-core/7.0.9/spring-core-7.0.9.jar</tspan></text>
|
|
<text x="24" y="1222" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">spring-tx 7.0.9 -> <cache>/org.springframework/spring-tx/7.0.9/spring-tx-7.0.9.jar</tspan></text>
|
|
<text x="24" y="1244" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">jakarta.persistence-api 3.2.0 -> <cache>/jakarta.persistence/jakarta.persistence-api/3.2.0/jakarta.persistence-api-3.2.0.jar</tspan></text>
|
|
<text x="24" y="1266" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">slf4j-api 2.0.18 -> <cache>/org.slf4j/slf4j-api/2.0.18/slf4j-api-2.0.18.jar</tspan></text>
|
|
<text x="24" y="1288" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># app-bootstrap 의 락파일에 querydsl 이 있는가: 0</tspan></text>
|
|
<text x="24" y="1310" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
|
|
<text x="24" y="1332" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 제한 없음 명세 팩토리가 어느 람다에 링크되는가</tspan></text>
|
|
<text x="24" y="1354" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">BootstrapMethods:</tspan></text>
|
|
<text x="24" y="1376" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> 0: #232 REF_invokeStatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$</tspan></text>
|
|
<text x="24" y="1398" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> Method arguments:</tspan></text>
|
|
<text x="24" y="1420" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> #233 (Ljakarta/persistence/criteria/Root;Ljakarta/persistence/criteria/CriteriaQuery;Ljakarta/persistenc</tspan></text>
|
|
<text x="24" y="1442" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> #236 REF_invokeStatic org/springframework/data/jpa/domain/Specification.lambda$0:(Ljakarta/persistence/c</tspan></text>
|
|
<text x="24" y="1464" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> #237 (Ljakarta/persistence/criteria/Root;Ljakarta/persistence/criteria/CriteriaQuery;Ljakarta/persistenc</tspan></text>
|
|
<text x="24" y="1486" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 그 람다의 본문</tspan></text>
|
|
<text x="24" y="1508" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> private static jakarta.persistence.criteria.Predicate lambda$0(jakarta.persistence.criteria.Root, jakarta.persistence.criteria</tspan><tspan x="24" dy="22">.CriteriaQuery, jakarta.persistence.criteria.CriteriaBuilder);</tspan></text>
|
|
<text x="24" y="1552" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> Code:</tspan></text>
|
|
<text x="24" y="1574" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> 0: aconst_null</tspan></text>
|
|
<text x="24" y="1596" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> 1: areturn</tspan></text>
|
|
<text x="24" y="1618" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
|
|
<text x="24" y="1640" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 그 명세와 자바 널을 두 검사에 각각 넣는다</tspan></text>
|
|
<text x="24" y="1662" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">Specification.unrestricted() 가 널인가 : false</tspan></text>
|
|
<text x="24" y="1684" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">그 명세의 toPredicate 가 돌려주는 값 : null</tspan></text>
|
|
<text x="24" y="1706" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">requireBounded(토큰 없이) : 통과</tspan></text>
|
|
<text x="24" y="1728" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">requirePredicate : 통과</tspan></text>
|
|
<text x="24" y="1750" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">requireBounded(널 명세) : 거절 — a specification query requires a bounded predicate, or the explicit 'allow-unbounded-scan' </tspan><tspan x="24" dy="22">token</tspan></text>
|
|
<text x="24" y="1794" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">requirePredicate(널 명세) : 거절 — a specification query requires a bounded predicate</tspan></text>
|
|
<text x="24" y="1816" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
|
|
<text x="24" y="1838" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 페이지 경계 검사는 그대로 남아 있다</tspan></text>
|
|
<text x="24" y="1860" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">34: if (pageable.isUnpaged()) {</tspan></text>
|
|
<text x="24" y="1882" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">35- throw new IllegalArgumentException(</tspan></text>
|
|
<text x="24" y="1904" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">36- "a specification query requires a bounded page; unpaged reads whatever the table holds");</tspan></text>
|
|
<text x="24" y="1926" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">37- }</tspan></text>
|
|
<text x="24" y="1948" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 반면 requirePredicate 는 Pageable 을 받지 않는다</tspan></text>
|
|
<text x="24" y="1970" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">47: public static void requirePredicate(Specification<?> specification) {</tspan></text>
|
|
<text x="24" y="1992" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
|
|
<text x="24" y="2014" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 형제 정책에 Querydsl 쪽 대응물을 넣는다</tspan></text>
|
|
<text x="24" y="2036" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">빈 BooleanBuilder 가 널인가 : false</tspan></text>
|
|
<text x="24" y="2058" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">hasValue : false</tspan></text>
|
|
<text x="24" y="2080" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">PredicatePolicy 판정 : 통과</tspan></text>
|
|
<text x="24" y="2102" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
|
|
<text x="24" y="2124" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 형제 쪽 진입점은 항상 limit 을 붙이고, 그 리프에서 Querydsl 은 compileOnly 다</tspan></text>
|
|
<text x="24" y="2146" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> JPAQuery<T> query = queryFactory.selectFrom(root);</tspan></text>
|
|
<text x="24" y="2168" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> if (predicate != null) {</tspan></text>
|
|
<text x="24" y="2190" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> query = query.where(predicate);</tspan></text>
|
|
<text x="24" y="2212" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> }</tspan></text>
|
|
<text x="24" y="2234" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> return query.offset(page.offset()).limit(page.size()).setHint(COMMENT_HINT, name.value());</tspan></text>
|
|
<text x="24" y="2256" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> }</tspan></text>
|
|
<text x="24" y="2278" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">69: compileOnly 'com.querydsl:querydsl-jpa:5.1.0:jakarta'</tspan></text>
|
|
<text x="24" y="2300" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> * <p>Querydsl is an Advanced opt-in and is {@code compileOnly} for this leaf, so the Stable runtime</tspan></text>
|
|
<text x="24" y="2322" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> * classpath never carries it. A deployment that wants it adds the artifact; one that does not is</tspan></text>
|
|
<text x="24" y="2344" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"> * unaffected by the existence of this class.</tspan></text>
|
|
</svg>
|