├── .editorconfig
├── .gitignore
├── README.md
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── img
├── aggregate.drawio
├── aggregate.jpg
├── db.drawio
└── db.jpg
├── settings.gradle
├── spring-data-jdbc-plus-sql-groovy-sample
├── build.gradle
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── navercorp
│ │ │ └── spring
│ │ │ └── sql
│ │ │ └── groovy
│ │ │ ├── Application.java
│ │ │ ├── account
│ │ │ ├── Account.java
│ │ │ ├── AccountRepository.java
│ │ │ ├── AccountRepositoryCustom.java
│ │ │ ├── AccountRepositoryImpl.java
│ │ │ └── AccountState.java
│ │ │ ├── comment
│ │ │ ├── Comment.java
│ │ │ ├── CommentContent.java
│ │ │ └── CommentRepository.java
│ │ │ ├── config
│ │ │ └── JdbcConfig.java
│ │ │ ├── issue
│ │ │ ├── Issue.java
│ │ │ ├── IssueAttachedLabel.java
│ │ │ ├── IssueContent.java
│ │ │ ├── IssueRepository.java
│ │ │ ├── IssueRepositoryCustom.java
│ │ │ ├── IssueRepositoryImpl.java
│ │ │ ├── Status.java
│ │ │ └── sql
│ │ │ │ └── IssueSql.groovy
│ │ │ ├── label
│ │ │ ├── Label.java
│ │ │ └── LabelRepository.java
│ │ │ ├── query
│ │ │ ├── QuerySideDao.java
│ │ │ ├── criteria
│ │ │ │ ├── IssueGridCriteria.java
│ │ │ │ └── IssueViewCriteria.java
│ │ │ ├── grid
│ │ │ │ ├── AccountGrid.java
│ │ │ │ ├── CommentGrid.java
│ │ │ │ ├── IssueGrid.java
│ │ │ │ └── IssueRepoGrid.java
│ │ │ ├── sql
│ │ │ │ └── QuerySideSql.groovy
│ │ │ └── view
│ │ │ │ ├── AccountView.java
│ │ │ │ ├── CommentView.java
│ │ │ │ ├── IssueLabelView.java
│ │ │ │ ├── IssueRepoView.java
│ │ │ │ └── IssueView.java
│ │ │ ├── repo
│ │ │ ├── Repo.java
│ │ │ └── RepoRepository.java
│ │ │ └── support
│ │ │ ├── EncryptString.java
│ │ │ ├── Encryptor.java
│ │ │ └── SimpleEncryptor.java
│ └── resources
│ │ ├── application.yml
│ │ └── db
│ │ └── changelog
│ │ ├── changelog-0.0.1.xml
│ │ └── changelog-master.xml
│ └── test
│ └── java
│ └── com
│ └── navercorp
│ └── spring
│ └── sql
│ └── groovy
│ ├── account
│ └── AccountRepositoryTest.java
│ ├── comment
│ └── CommentRepositoryTest.java
│ ├── issue
│ └── IssueRepositoryTest.java
│ ├── label
│ └── LabelRepositoryTest.java
│ ├── query
│ └── QuerySideDaoTest.java
│ ├── repo
│ └── RepoRepositoryTest.java
│ └── test
│ └── DataInitializeExecutionListener.java
├── spring-data-jdbc-sample
├── build.gradle
└── src
│ ├── main
│ ├── java
│ │ └── spring
│ │ │ └── data
│ │ │ └── jdbc
│ │ │ ├── Application.java
│ │ │ ├── account
│ │ │ ├── Account.java
│ │ │ ├── AccountRepository.java
│ │ │ ├── AccountRepositoryCustom.java
│ │ │ ├── AccountRepositoryImpl.java
│ │ │ └── AccountState.java
│ │ │ ├── comment
│ │ │ ├── Comment.java
│ │ │ ├── CommentContent.java
│ │ │ └── CommentRepository.java
│ │ │ ├── config
│ │ │ └── JdbcConfig.java
│ │ │ ├── issue
│ │ │ ├── Issue.java
│ │ │ ├── IssueAttachedLabel.java
│ │ │ ├── IssueContent.java
│ │ │ ├── IssueRepository.java
│ │ │ ├── IssueRepositoryCustom.java
│ │ │ ├── IssueRepositoryImpl.java
│ │ │ ├── Status.java
│ │ │ └── sql
│ │ │ │ └── IssueSql.java
│ │ │ ├── label
│ │ │ ├── Label.java
│ │ │ └── LabelRepository.java
│ │ │ ├── repo
│ │ │ ├── Repo.java
│ │ │ └── RepoRepository.java
│ │ │ └── support
│ │ │ ├── AggregateReferenceValueExtractor.java
│ │ │ ├── EncryptString.java
│ │ │ ├── Encryptor.java
│ │ │ ├── SimpleEncryptor.java
│ │ │ ├── WithInsert.java
│ │ │ └── WithInsertImpl.java
│ └── resources
│ │ ├── META-INF
│ │ └── services
│ │ │ └── javax.validation.valueextraction.ValueExtractor
│ │ ├── application.yml
│ │ └── db
│ │ └── changelog
│ │ ├── changelog-0.0.1.xml
│ │ └── changelog-master.xml
│ └── test
│ └── java
│ └── spring
│ └── data
│ └── jdbc
│ ├── account
│ └── AccountRepositoryTest.java
│ ├── comment
│ └── CommentRepositoryTest.java
│ ├── issue
│ └── IssueRepositoryTest.java
│ ├── label
│ └── LabelRepositoryTest.java
│ ├── repo
│ └── RepoRepositoryTest.java
│ └── test
│ └── DataInitializeExecutionListener.java
├── spring-data-jpa-sample
├── build.gradle
└── src
│ ├── main
│ ├── java
│ │ └── spring
│ │ │ └── data
│ │ │ └── jpa
│ │ │ ├── Application.java
│ │ │ ├── account
│ │ │ ├── Account.java
│ │ │ ├── AccountRepository.java
│ │ │ └── AccountState.java
│ │ │ ├── comment
│ │ │ ├── Comment.java
│ │ │ ├── CommentContent.java
│ │ │ └── CommentRepository.java
│ │ │ ├── issue
│ │ │ ├── Issue.java
│ │ │ ├── IssueAttachedLabel.java
│ │ │ ├── IssueContent.java
│ │ │ ├── IssueRepository.java
│ │ │ └── Status.java
│ │ │ ├── label
│ │ │ ├── Label.java
│ │ │ └── LabelRepository.java
│ │ │ └── repo
│ │ │ ├── Repo.java
│ │ │ └── RepoRepository.java
│ └── resources
│ │ └── application.yml
│ └── test
│ └── java
│ └── spring
│ └── data
│ └── jpa
│ ├── account
│ └── AccountRepositoryTest.java
│ ├── comment
│ └── CommentRepositoryTest.java
│ ├── issue
│ └── IssueRepositoryTest.java
│ ├── label
│ └── LabelRepositoryTest.java
│ ├── repo
│ └── RepoRepositoryTest.java
│ └── test
│ └── DataInitializeExecutionListener.java
└── spring-data-r2dbc-sample
├── build.gradle
├── lombok.config
└── src
├── main
├── java
│ └── spring
│ │ └── data
│ │ └── r2dbc
│ │ ├── Application.java
│ │ ├── account
│ │ ├── Account.java
│ │ ├── AccountRepository.java
│ │ ├── AccountRepositoryCustom.java
│ │ ├── AccountRepositoryImpl.java
│ │ └── AccountState.java
│ │ ├── comment
│ │ ├── Comment.java
│ │ ├── CommentContent.java
│ │ └── CommentRepository.java
│ │ ├── config
│ │ └── R2dbcConfig.java
│ │ ├── issue
│ │ ├── Issue.java
│ │ ├── IssueAttachedLabel.java
│ │ ├── IssueAttachedLabelRepository.java
│ │ ├── IssueContent.java
│ │ ├── IssueRepository.java
│ │ ├── IssueRepositoryCustom.java
│ │ ├── IssueRepositoryImpl.java
│ │ ├── Status.java
│ │ └── sql
│ │ │ └── IssueSql.java
│ │ ├── label
│ │ ├── Label.java
│ │ └── LabelRepository.java
│ │ ├── repo
│ │ ├── Repo.java
│ │ └── RepoRepository.java
│ │ └── support
│ │ ├── ClobJsonReadingConverter.java
│ │ ├── ClobReadingConverter.java
│ │ ├── EncryptString.java
│ │ ├── Encryptor.java
│ │ ├── JsonStringWritingConverter.java
│ │ ├── PersistableMarkNotNewAop.java
│ │ ├── RepositoryValidationAop.java
│ │ ├── SimpleEncryptor.java
│ │ ├── WithInsert.java
│ │ └── WithInsertImpl.java
└── resources
│ ├── application.yml
│ └── db
│ └── changelog
│ ├── changelog-0.0.1.xml
│ └── changelog-master.xml
└── test
└── java
└── spring
└── data
└── r2dbc
├── account
└── AccountRepositoryTest.java
├── comment
└── CommentRepositoryTest.java
├── issue
└── IssueRepositoryTest.java
├── label
└── LabelRepositoryTest.java
├── repo
└── RepoRepositoryTest.java
└── test
└── DataInitializeExecutionListener.java
/.editorconfig:
--------------------------------------------------------------------------------
1 | # top-most EditorConfig file
2 | root = true
3 |
4 | [*.{kt, kts}]
5 | disabled_rules = import-ordering
6 |
7 | # 4 space indentation
8 | [*.java]
9 | charset = utf-8
10 | end_of_line = lf
11 | indent_size = 4
12 | indent_style = space
13 | trim_trailing_whitespace = true
14 | insert_final_newline = true
15 | max_line_length = 120
16 | tab_width = 4
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | build/
3 | !gradle/wrapper/gradle-wrapper.jar
4 | /bin/
5 | /env.bat
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 | out/
22 |
23 | ### Mac OS ###
24 | .DS_Store
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Spring Data Sample Codes
2 |
3 | [발표 자료](https://docs.google.com/presentation/d/1E7Y_L8TO6ZRZfFjBO6f_GBZxzdV0Klw0XNuH1Kv4JWA/edit)
4 |
5 | 
6 | 
7 |
8 | ## [Spring Data JPA Sample](./spring-data-jpa-sample)
9 |
10 | - 2.2.6.RELEASE
11 | - hibernate-orm 5.4.12.Final
12 | - spring-data-commons 2.6.6.RELEASE
13 |
14 | ## [Spring Data JDBC Sample](./spring-data-jdbc-sample)
15 |
16 | - 2.0.0.RC2
17 | - spring-data-relational 2.0.0.RC2
18 | - spring-data-commons 2.3.0.RC2
19 |
20 | ## [Spring Data R2DBC Sample](./spring-data-r2dbc-sample)
21 |
22 | - 1.1.0.RC2
23 | - spring-data-relational 2.0.0.RC2
24 | - spring-data-commons 2.3.0.RC2
25 |
26 | ## [Spring Data JDBC Plus Sample](./spring-data-jdbc-plus-sql-groovy-sample)
27 |
28 | - [Spring JDBC Plus](https://github.com/naver/spring-jdbc-plus) 2.0.0.RC2
29 | - spring-data-jdbc 2.0.0.RC2
30 | - spring-data-relational 2.0.0.RC2
31 | - spring-data-commons 2.3.0.RC2
32 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | import org.springframework.boot.gradle.plugin.SpringBootPlugin
2 |
3 | buildscript {
4 | repositories {
5 | mavenCentral()
6 | mavenLocal()
7 | maven {
8 | url "https://repo.spring.io/milestone/"
9 | }
10 | }
11 | dependencies {
12 | classpath("org.springframework.boot:spring-boot-gradle-plugin:2.2.6.RELEASE")
13 | classpath("org.hibernate.build.gradle:gradle-maven-publish-auth:2.0.1")
14 | }
15 | }
16 |
17 | allprojects {
18 | group = "com.navercorp"
19 | version "1.0.0-SNAPSHOT"
20 | }
21 |
22 | subprojects {
23 | apply plugin: "java"
24 | apply plugin: "idea"
25 | apply plugin: "io.spring.dependency-management"
26 | apply plugin: "maven"
27 |
28 | sourceCompatibility = JavaVersion.VERSION_11
29 | targetCompatibility = JavaVersion.VERSION_11
30 |
31 | repositories {
32 | mavenCentral()
33 | maven {
34 | url "https://repo.spring.io/milestone/"
35 | }
36 | maven {
37 | name "navercorp.release"
38 | url "http://repo.navercorp.com/maven2/"
39 | }
40 | maven {
41 | name "navercorp.snapshot"
42 | url "http://repo.navercorp.com/m2-snapshot-repository/"
43 | }
44 | }
45 |
46 | dependencies {
47 | compileOnly("com.google.code.findbugs:jsr305:3.0.2")
48 | testCompile("org.assertj:assertj-core")
49 | }
50 |
51 | dependencyManagement {
52 | imports {
53 | mavenBom SpringBootPlugin.BOM_COORDINATES
54 | }
55 | }
56 |
57 | test {
58 | useJUnitPlatform()
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mhyeon-lee/spring-data-sample-codes/99c96ad491e379682969e8342f70073749493086/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS='"-Xmx64m"'
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS="-Xmx64m"
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/img/aggregate.drawio:
--------------------------------------------------------------------------------
1 | 7Vtdc5s4FP01fnQGSWDjx9hNdzvT3ck0s7vtU0cG2WaDkVfIjd1fvwIkPiSMXX9g4sQvQRdJSOceHeleSA9NlpvfGF4t/qA+CXvQ8jc99KEHIbBGUPxJLNvM4oJBZpizwM9MVmF4Cn4S1VJa14FPYmnLTJzSkAerqtGjUUQ8XrFhxuhLtdqMhn7FsMJzYhiePBya1n8Cny/kLOCwsP9OgvlCPRkMRtmdJVaV5UziBfbpS8mEHnpowijl2dVyMyFhAl4Vl4877uYDYyTihzQI19GXx+8wht7fwV8OvZ/8N930gZN18wOHazljOVq+VRAs+DIUV6CHxrIyYZxsdg4D5JMTrCB0STjbiiqyge1KAkhCQADv5CBeCoDBUMK4KIOLZFMsnTrPey/mLS7k1H8FhsF+GIT/VsmlR5crGqWzHf9LON8qXrjKkBPCPhSyBt/sBBIYoCmmlTFTNkZCzIMfVVbX4Sif90gDMbj8YX1FeOm1YbUDOpvFhBtuyAd9gmeG1yYoct2r09PtIj2H7/TsA3R1esKrs9PuIjvROzv7ALTNTnWe2FaLJZyRg2rIORjuBvU0csIuknMPiG+CnKMrcxMiE+dacsKheylyWh0k5+idm31TNz/Fsbg0nMMZfc4DQzGNMaPryCe+ZC1mngxphavR+GURcPK0wl5ieREBs7CVOI7DYB4lrhYOIkwYZjTiqv3BTm1eBNC2q6tgYBkeBVaNS3Pj2VeBqdAp2PecY29B/M94muQUXj3yyK0AXxtW2G4d8PBCwJtn1xT4iZh7MqfXD/lA47ozMiFXktsO5OZR+d7zBIq3gLYDqgy3a9BuV1nM5NaELpe3wW1dyK+PtplDk2jfjqDY+xmOWpVwMzv2hazoDSCti0ndab1lfptJuFs5mhjKraLm64ENzPDQ2yEjJPLvkzc9ojQNqfcsMBGmj0GoICyhSfw5eZJNKeMLOqcRDh8Ka443y2Y5ToANPBzeSzuniYNMH4cJFx5pHPCAJvVCMis3/6zdnlLO6TJ3XzKuI52ngpUTYy0R+1Y4ACwt2orpmnlEtiq8a3QERuBuT1ccsznhRlfnit6gGVYDgzWMxMFPPE2LVv2S01yoGJC7LnX5GHvP83SBT2hIWdo5mqU/bbFaubfly0r59F4eLh+VS2qO18/Ejr4NKi7ttxaKq/P5uxC0JgTVgyUCRwuBpQmB0dWlhcCMcG9XCLKFcsNCYMbOuJwiijuqB2QT8K8Jt+6gI4vf1EPF9YeN5F1a2KpCJMD6qqolhW9pFzbKDUXDtFRp+UhYIPBOzoup8dKaJGBPRaFpn8rqZSu+yc2taJw6XkoWO1BL8R+scUNH0zijq0trnJnk+PN2Nc5uReOG1dcOKo3YgsaZORQm4vlPfpO20RWJKtJmHSttOzhQp2xJxz6OF3lUm90u0cJKfzXiowto509EyNZPRNqnFIeqhe2i5o4urRVmCsNjBHPij7dvkmH5NpvvnNk26+zZZA/fF/fud3s+VDkbhasbHhyi4yjsONW1APSOLk3hmrzQm6Zwd0RSe1dvH0cw/fs2vZ8L8wuZuaMgeSna1hb8K9HFCfR6dUmJkSY7zpFbsN4RVPmltvhlflqS+uaN8qsIjgfuqBwd31l7AmRR0KPcYjeXobba0PfFzIdv53vDXHjott/89fS5RNmqiukAWMctG9t2mjvasWwEgfG2VG2VVIh3DxjYVuU5jnzjuvM4gkBTfXGRjeC8a9hMSXcgSsvXVGtnkEwziiVcTm9Zjau3K9uKM9BefFpH5oH0jpDT8rHFTI5241h8LVZ2lWEQHnlw0TsCzkhlHk/mmCgW/4eYVS/+mxM9/A8=
--------------------------------------------------------------------------------
/img/aggregate.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mhyeon-lee/spring-data-sample-codes/99c96ad491e379682969e8342f70073749493086/img/aggregate.jpg
--------------------------------------------------------------------------------
/img/db.drawio:
--------------------------------------------------------------------------------
1 | 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
--------------------------------------------------------------------------------
/img/db.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mhyeon-lee/spring-data-sample-codes/99c96ad491e379682969e8342f70073749493086/img/db.jpg
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = "spring-data-sample-codes"
2 |
3 | include "spring-data-jpa-sample"
4 | include "spring-data-jdbc-sample"
5 | include "spring-data-r2dbc-sample"
6 | include "spring-data-jdbc-plus-sql-groovy-sample"
7 |
8 |
--------------------------------------------------------------------------------
/spring-data-jdbc-plus-sql-groovy-sample/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id "java"
3 | id "groovy"
4 | }
5 |
6 | compileJava {
7 | dependsOn compileGroovy
8 | }
9 |
10 | compileGroovy {
11 | options.encoding = "UTF-8"
12 | groovyOptions.encoding = "UTF-8"
13 | }
14 |
15 | tasks.withType(JavaCompile) { task ->
16 | dependsOn task.name.replace("Java", "Groovy")
17 | }
18 |
19 | tasks.withType(GroovyCompile) {
20 | dependsOn = []
21 | }
22 |
23 | sourceSets {
24 | main {
25 | java { srcDirs = [] }
26 | groovy { srcDirs += ["src/main/java"] }
27 | }
28 | }
29 |
30 | if (project.convention.findPlugin(JavaPluginConvention)) {
31 | // Change the output directory for the main and test source sets back to the old path
32 | sourceSets.main.java.outputDir = new File(buildDir, "classes/main")
33 | sourceSets.main.groovy.outputDir = new File(buildDir, "classes/main")
34 | sourceSets.test.java.outputDir = new File(buildDir, "classes/test")
35 | sourceSets.test.groovy.outputDir = new File(buildDir, "classes/test")
36 | }
37 |
38 | dependencies {
39 | implementation("com.navercorp.spring:spring-boot-starter-data-jdbc-plus-sql:2.0.0.RC2")
40 | implementation("com.navercorp.spring:spring-boot-starter-data-jdbc-plus-repository:2.0.0.RC2")
41 |
42 | implementation("org.springframework.boot:spring-boot-starter")
43 | implementation("org.springframework.data:spring-data-jdbc:2.0.0.RC2")
44 | implementation("org.springframework.data:spring-data-relational:2.0.0.RC2")
45 | implementation("org.springframework.data:spring-data-commons:2.3.0.RC2")
46 | implementation("org.liquibase:liquibase-core")
47 |
48 | implementation("org.codehaus.groovy:groovy:3.0.3")
49 |
50 | compileOnly("org.projectlombok:lombok")
51 | annotationProcessor("org.projectlombok:lombok")
52 |
53 | runtimeOnly("com.h2database:h2")
54 |
55 | testImplementation("org.springframework.boot:spring-boot-starter-test") {
56 | exclude group: "org.junit.vintage", module: "junit-vintage-engine"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/spring-data-jdbc-plus-sql-groovy-sample/src/main/java/com/navercorp/spring/sql/groovy/Application.java:
--------------------------------------------------------------------------------
1 | package com.navercorp.spring.sql.groovy;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class Application {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(Application.class, args);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/spring-data-jdbc-plus-sql-groovy-sample/src/main/java/com/navercorp/spring/sql/groovy/account/Account.java:
--------------------------------------------------------------------------------
1 | package com.navercorp.spring.sql.groovy.account;
2 |
3 | import com.navercorp.spring.sql.groovy.support.EncryptString;
4 | import lombok.Builder;
5 | import lombok.EqualsAndHashCode;
6 | import lombok.Getter;
7 | import lombok.ToString;
8 | import org.springframework.data.annotation.Id;
9 | import org.springframework.data.relational.core.mapping.Table;
10 |
11 | import java.time.Instant;
12 | import java.util.UUID;
13 |
14 | @Table
15 | @Builder
16 | @Getter
17 | @EqualsAndHashCode(of = "id")
18 | @ToString
19 | public class Account {
20 | @Id
21 | private UUID id;
22 |
23 | private String loginId;
24 |
25 | private String name;
26 |
27 | private AccountState state;
28 |
29 | private EncryptString email;
30 |
31 | @Builder.Default
32 | private Instant createdAt = Instant.now();
33 |
34 | public void lock() {
35 | this.state = AccountState.LOCKED;
36 | }
37 |
38 | public void delete() {
39 | this.state = AccountState.DELETED;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/spring-data-jdbc-plus-sql-groovy-sample/src/main/java/com/navercorp/spring/sql/groovy/account/AccountRepository.java:
--------------------------------------------------------------------------------
1 | package com.navercorp.spring.sql.groovy.account;
2 |
3 | import com.navercorp.spring.data.jdbc.plus.repository.JdbcRepository;
4 |
5 | import java.util.EnumSet;
6 | import java.util.Optional;
7 | import java.util.Set;
8 | import java.util.UUID;
9 |
10 | public interface AccountRepository extends JdbcRepository, AccountRepositoryCustom {
11 | @Override
12 | void deleteById(UUID id);
13 |
14 | @Override
15 | void delete(Account entity);
16 |
17 | @Override
18 | void deleteAll(Iterable extends Account> entities);
19 |
20 | @Override
21 | void deleteAll();
22 |
23 | Optional findByIdAndStateIn(UUID uuid, Set states);
24 |
25 | default Optional findByIdExcludeDeleted(UUID id) {
26 | return this.findByIdAndStateIn(id, EnumSet.of(AccountState.ACTIVE, AccountState.LOCKED));
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/spring-data-jdbc-plus-sql-groovy-sample/src/main/java/com/navercorp/spring/sql/groovy/account/AccountRepositoryCustom.java:
--------------------------------------------------------------------------------
1 | package com.navercorp.spring.sql.groovy.account;
2 |
3 | public interface AccountRepositoryCustom {
4 | }
5 |
--------------------------------------------------------------------------------
/spring-data-jdbc-plus-sql-groovy-sample/src/main/java/com/navercorp/spring/sql/groovy/account/AccountRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package com.navercorp.spring.sql.groovy.account;
2 |
3 | import org.springframework.dao.TransientDataAccessResourceException;
4 | import org.springframework.data.jdbc.core.JdbcAggregateOperations;
5 | import org.springframework.transaction.annotation.Transactional;
6 |
7 | import java.util.UUID;
8 |
9 | public class AccountRepositoryImpl implements AccountRepositoryCustom {
10 | private final JdbcAggregateOperations jdbcAggregateOperations;
11 |
12 | public AccountRepositoryImpl(JdbcAggregateOperations jdbcAggregateOperations) {
13 | this.jdbcAggregateOperations = jdbcAggregateOperations;
14 | }
15 |
16 | @Transactional
17 | public void deleteById(UUID id) {
18 | Account account = this.jdbcAggregateOperations.findById(id, Account.class);
19 | if (account == null) {
20 | throw new TransientDataAccessResourceException("account does not exist.id: " + id);
21 | }
22 |
23 | this.delete(account);
24 | }
25 |
26 | @Transactional
27 | public void delete(Account entity) {
28 | entity.delete();
29 | this.jdbcAggregateOperations.update(entity);
30 | }
31 |
32 | @Transactional
33 | public void deleteAll(Iterable extends Account> entities) {
34 | entities.forEach(this::delete);
35 | }
36 |
37 | @Transactional
38 | public void deleteAll() {
39 | Iterable accounts = this.jdbcAggregateOperations.findAll(Account.class);
40 | this.deleteAll(accounts);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/spring-data-jdbc-plus-sql-groovy-sample/src/main/java/com/navercorp/spring/sql/groovy/account/AccountState.java:
--------------------------------------------------------------------------------
1 | package com.navercorp.spring.sql.groovy.account;
2 |
3 | public enum AccountState {
4 | ACTIVE, LOCKED, DELETED
5 | }
6 |
--------------------------------------------------------------------------------
/spring-data-jdbc-plus-sql-groovy-sample/src/main/java/com/navercorp/spring/sql/groovy/comment/Comment.java:
--------------------------------------------------------------------------------
1 | package com.navercorp.spring.sql.groovy.comment;
2 |
3 | import com.navercorp.spring.sql.groovy.account.Account;
4 | import com.navercorp.spring.sql.groovy.issue.Issue;
5 | import lombok.EqualsAndHashCode;
6 | import lombok.Getter;
7 | import lombok.ToString;
8 | import org.springframework.data.annotation.Id;
9 | import org.springframework.data.annotation.Version;
10 | import org.springframework.data.jdbc.core.mapping.AggregateReference;
11 | import org.springframework.data.relational.core.mapping.Column;
12 | import org.springframework.data.relational.core.mapping.Table;
13 |
14 | import java.time.Instant;
15 | import java.util.UUID;
16 |
17 | @Table
18 | @Getter
19 | @EqualsAndHashCode(of = "id")
20 | @ToString
21 | public class Comment {
22 | @Id
23 | private Long id;
24 |
25 | @Version
26 | private long version;
27 |
28 | private AggregateReference issueId;
29 |
30 | @Column("ID") // PK MAPPING, default: "COMMENT"
31 | private CommentContent content;
32 |
33 | private AggregateReference createdBy;
34 |
35 | private Instant createdAt;
36 |
37 | public Comment(
38 | AggregateReference issueId,
39 | CommentContent content,
40 | AggregateReference createdBy) {
41 |
42 | this.issueId = issueId;
43 | this.content = content;
44 | this.createdBy = createdBy;
45 | this.createdAt = Instant.now();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/spring-data-jdbc-plus-sql-groovy-sample/src/main/java/com/navercorp/spring/sql/groovy/comment/CommentContent.java:
--------------------------------------------------------------------------------
1 | package com.navercorp.spring.sql.groovy.comment;
2 |
3 | import lombok.*;
4 | import org.springframework.data.annotation.Id;
5 | import org.springframework.data.annotation.PersistenceConstructor;
6 |
7 | @Value
8 | @AllArgsConstructor(access = AccessLevel.PRIVATE, onConstructor = @__(@PersistenceConstructor))
9 | public class CommentContent {
10 | @Id
11 | @With
12 | Long id;
13 |
14 | String body;
15 |
16 | String mimeType;
17 |
18 | public CommentContent(String body, String mimeType) {
19 | this.id = null;
20 | this.body = body;
21 | this.mimeType = mimeType;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/spring-data-jdbc-plus-sql-groovy-sample/src/main/java/com/navercorp/spring/sql/groovy/comment/CommentRepository.java:
--------------------------------------------------------------------------------
1 | package com.navercorp.spring.sql.groovy.comment;
2 |
3 | import org.springframework.data.repository.CrudRepository;
4 |
5 | public interface CommentRepository extends CrudRepository {
6 | }
7 |
--------------------------------------------------------------------------------
/spring-data-jdbc-plus-sql-groovy-sample/src/main/java/com/navercorp/spring/sql/groovy/config/JdbcConfig.java:
--------------------------------------------------------------------------------
1 | package com.navercorp.spring.sql.groovy.config;
2 |
3 | import com.navercorp.spring.data.jdbc.plus.sql.config.JdbcPlusSqlConfiguration;
4 | import com.navercorp.spring.data.jdbc.plus.sql.parametersource.EntityConvertibleSqlParameterSourceFactory;
5 | import com.navercorp.spring.data.jdbc.plus.sql.parametersource.SqlParameterSourceFactory;
6 | import com.navercorp.spring.jdbc.plus.support.parametersource.ConvertibleParameterSourceFactory;
7 | import com.navercorp.spring.jdbc.plus.support.parametersource.converter.DefaultJdbcParameterSourceConverter;
8 | import com.navercorp.spring.jdbc.plus.support.parametersource.converter.JdbcParameterSourceConverter;
9 | import com.navercorp.spring.jdbc.plus.support.parametersource.converter.Unwrapper;
10 | import com.navercorp.spring.sql.groovy.label.Label.LabelAfterSaveEventListener;
11 | import com.navercorp.spring.sql.groovy.repo.Repo.RepoBeforeSaveCallback;
12 | import com.navercorp.spring.sql.groovy.support.EncryptString;
13 | import com.navercorp.spring.sql.groovy.support.Encryptor;
14 | import com.navercorp.spring.sql.groovy.support.SimpleEncryptor;
15 | import org.springframework.context.annotation.Bean;
16 | import org.springframework.context.annotation.Configuration;
17 | import org.springframework.core.convert.converter.Converter;
18 | import org.springframework.data.convert.ReadingConverter;
19 | import org.springframework.data.convert.WritingConverter;
20 | import org.springframework.data.jdbc.core.convert.JdbcConverter;
21 | import org.springframework.data.jdbc.core.convert.JdbcCustomConversions;
22 | import org.springframework.data.jdbc.core.mapping.AggregateReference;
23 | import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
24 | import org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration;
25 | import org.springframework.data.relational.core.dialect.Dialect;
26 | import org.springframework.data.relational.core.dialect.H2Dialect;
27 | import org.springframework.data.relational.core.sql.IdentifierProcessing;
28 | import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
29 | import org.springframework.lang.Nullable;
30 |
31 | import java.sql.Clob;
32 | import java.sql.SQLException;
33 | import java.util.List;
34 |
35 | @Configuration
36 | public class JdbcConfig extends AbstractJdbcConfiguration {
37 | @Bean
38 | public Dialect jdbcDialect(NamedParameterJdbcOperations operations) {
39 | return new H2Dialect() {
40 | @Override
41 | public IdentifierProcessing getIdentifierProcessing() {
42 | // SQL 작성시 컬럼 대상을 Quoting 해야 할 경우 불편하기 때문에 NONE 으로 설정한다.
43 | // Quoting 여부에 따른 호환은 DBMS 구현에 따른다.
44 | return IdentifierProcessing.create(
45 | IdentifierProcessing.Quoting.NONE, IdentifierProcessing.LetterCasing.UPPER_CASE);
46 | }
47 | };
48 | }
49 |
50 | @Bean
51 | @Override
52 | public JdbcCustomConversions jdbcCustomConversions() {
53 | Encryptor encryptor = new SimpleEncryptor();
54 | return new JdbcCustomConversions(List.of(
55 | new EncryptStringWritingConverter(encryptor),
56 | new EncryptStringReadingConverter(encryptor),
57 | new Converter() {
58 | @Nullable
59 | @Override
60 | public String convert(Clob clob) {
61 | try {
62 | return Math.toIntExact(clob.length()) == 0
63 | ? "" : clob.getSubString(1, Math.toIntExact(clob.length()));
64 |
65 | } catch (SQLException e) {
66 | throw new IllegalStateException("Failed to convert CLOB to String.", e);
67 | }
68 | }
69 | }));
70 | }
71 |
72 | @Bean
73 | LabelAfterSaveEventListener labelAfterSaveEventListener() {
74 | return new LabelAfterSaveEventListener();
75 | }
76 |
77 | @Bean
78 | RepoBeforeSaveCallback repoBeforeSaveCallback() {
79 | return new RepoBeforeSaveCallback();
80 | }
81 |
82 | @WritingConverter
83 | static class EncryptStringWritingConverter implements Converter {
84 | private final Encryptor encryptor;
85 |
86 | public EncryptStringWritingConverter(Encryptor encryptor) {
87 | this.encryptor = encryptor;
88 | }
89 |
90 | @Override
91 | public byte[] convert(EncryptString source) {
92 | return this.encryptor.encrypt(source.getValue());
93 | }
94 | }
95 |
96 | @ReadingConverter
97 | static class EncryptStringReadingConverter implements Converter {
98 | private final Encryptor encryptor;
99 |
100 | public EncryptStringReadingConverter(Encryptor encryptor) {
101 | this.encryptor = encryptor;
102 | }
103 |
104 | @Override
105 | public EncryptString convert(byte[] source) {
106 | String value = this.encryptor.decrypt(source);
107 | if (value == null) {
108 | return null;
109 | }
110 |
111 | return new EncryptString(value);
112 | }
113 | }
114 |
115 | @Configuration
116 | static class JdbcSqlConfig extends JdbcPlusSqlConfiguration {
117 | @Bean
118 | @Override
119 | public SqlParameterSourceFactory sqlParameterSourceFactory(
120 | JdbcMappingContext jdbcMappingContext, JdbcConverter jdbcConverter, Dialect dialect) {
121 |
122 | return new EntityConvertibleSqlParameterSourceFactory(
123 | this.parameterSourceConverter(),
124 | jdbcMappingContext,
125 | jdbcConverter,
126 | dialect.getIdentifierProcessing());
127 | }
128 |
129 | private ConvertibleParameterSourceFactory parameterSourceConverter() {
130 | JdbcParameterSourceConverter converter = new DefaultJdbcParameterSourceConverter(
131 | List.of(), List.of(new IdOnlyAggregateReferenceUnwrapper())
132 | );
133 | ConvertibleParameterSourceFactory parameterSourceFactory = new ConvertibleParameterSourceFactory(converter, null);
134 | parameterSourceFactory.setPaddingIterableParam(true);
135 | return parameterSourceFactory;
136 | }
137 | }
138 |
139 | static class IdOnlyAggregateReferenceUnwrapper implements Unwrapper {
140 | @Nullable
141 | @Override
142 | public Object unwrap(AggregateReference.IdOnlyAggregateReference source) {
143 | return source.getId();
144 | }
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/spring-data-jdbc-plus-sql-groovy-sample/src/main/java/com/navercorp/spring/sql/groovy/issue/Issue.java:
--------------------------------------------------------------------------------
1 | package com.navercorp.spring.sql.groovy.issue;
2 |
3 | import com.navercorp.spring.sql.groovy.account.Account;
4 | import com.navercorp.spring.sql.groovy.repo.Repo;
5 | import lombok.Builder;
6 | import lombok.EqualsAndHashCode;
7 | import lombok.Getter;
8 | import lombok.ToString;
9 | import org.springframework.data.annotation.Id;
10 | import org.springframework.data.annotation.Version;
11 | import org.springframework.data.jdbc.core.mapping.AggregateReference;
12 | import org.springframework.data.relational.core.mapping.Column;
13 | import org.springframework.data.relational.core.mapping.MappedCollection;
14 | import org.springframework.data.relational.core.mapping.Table;
15 |
16 | import java.time.Instant;
17 | import java.util.ArrayList;
18 | import java.util.Collections;
19 | import java.util.List;
20 | import java.util.UUID;
21 |
22 | @Table
23 | @Builder
24 | @Getter
25 | @EqualsAndHashCode(of = "id")
26 | @ToString
27 | public class Issue {
28 | @Id
29 | private UUID id;
30 |
31 | @Version
32 | private long version;
33 |
34 | private AggregateReference repoId;
35 |
36 | private Long issueNo;
37 |
38 | private Status status;
39 |
40 | private String title;
41 |
42 | @Column("ISSUE_ID") // default: "ISSUE"
43 | private IssueContent content;
44 |
45 | @MappedCollection(idColumn = "ISSUE_ID", keyColumn = "ATTACHED_AT")
46 | @Builder.Default
47 | private List attachedLabels = new ArrayList<>();
48 |
49 | private AggregateReference createdBy;
50 |
51 | @Builder.Default
52 | private Instant createdAt = Instant.now();
53 |
54 | public void changeContent(IssueContent content) {
55 | this.content = content;
56 | }
57 |
58 | public List getAttachedLabels() {
59 | return Collections.unmodifiableList(this.attachedLabels);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/spring-data-jdbc-plus-sql-groovy-sample/src/main/java/com/navercorp/spring/sql/groovy/issue/IssueAttachedLabel.java:
--------------------------------------------------------------------------------
1 | package com.navercorp.spring.sql.groovy.issue;
2 |
3 | import com.navercorp.spring.sql.groovy.label.Label;
4 | import lombok.Builder;
5 | import lombok.Value;
6 | import lombok.With;
7 | import org.springframework.data.annotation.Id;
8 | import org.springframework.data.jdbc.core.mapping.AggregateReference;
9 |
10 | import java.time.Instant;
11 | import java.util.UUID;
12 |
13 | @Value
14 | @Builder
15 | public class IssueAttachedLabel {
16 | @Id
17 | @With
18 | Long id;
19 |
20 | AggregateReference