Compare commits

...

26 Commits

Author SHA1 Message Date
Jordan Zimmerman
6781824f08 [maven-release-plugin] prepare for next development iteration 2023-07-03 09:57:59 +01:00
Jordan Zimmerman
2c34ffd4ca [maven-release-plugin] prepare release record-builder-37 2023-07-03 09:57:53 +01:00
Paweł Łabaj
c6cf23956f Fixes Randgalt/record-builder/#153 (#154) 2023-07-03 09:46:23 +01:00
Jordan Zimmerman
1b22341b58 [maven-release-plugin] prepare for next development iteration 2023-03-29 17:50:15 +01:00
Jordan Zimmerman
409fb883e4 [maven-release-plugin] prepare release record-builder-36 2023-03-29 17:50:09 +01:00
Jordan Zimmerman
141362845e With interface shouldn't use prefix option (#132) 2023-03-29 10:03:17 +01:00
Stefan Bischof
183ab67c1a handle RecordBuilder.Options on packages (#149)
Thanks for the PR
2023-03-29 08:53:06 +01:00
Jordan Zimmerman
685a31b56b Various clean ups (#150) 2023-03-29 08:07:59 +01:00
Varun Upadhyay
f3303c2386 Fix javadoc builder core (#144)
Thank you for the PR
2023-03-28 08:36:40 +01:00
tison
e12d359696 Upgrade license-maven-plugin version and reformat (#145) 2023-03-12 07:56:15 +00:00
Dmitrii Priporov
4924f7b3ea issue-122: updated add1GetterMethod logic in useImmutableCollections=true case (#138) 2023-02-07 07:45:32 +00:00
Jordan Zimmerman
3e1d7d69d0 Update README.md 2023-01-09 09:17:39 +00:00
Jordan Zimmerman
22f827d81a [maven-release-plugin] prepare for next development iteration 2023-01-09 09:12:02 +00:00
Jordan Zimmerman
91c6090ace [maven-release-plugin] prepare release record-builder-35 2023-01-09 09:11:57 +00:00
David Morris
098a5c8bfd Configurable modifiers on static builders (#135) 2023-01-07 13:28:22 +00:00
David Morris
e2f17d4087 Adding of maven wrapper (#136) 2023-01-07 13:25:29 +00:00
David Morris
2b3e895cf6 initial .gitignore (#137) 2023-01-06 08:10:49 +00:00
Sebastian Hoß
117c789593 use configured build method name instead of hard-coded name (#133)
Co-authored-by: Sebastian Hoß <seb@hoß.de>
2022-12-15 20:45:43 +00:00
Jordan Zimmerman
4ff80fb20c [maven-release-plugin] prepare for next development iteration 2022-08-02 05:05:19 +02:00
Jordan Zimmerman
abfc12bdb0 [maven-release-plugin] prepare release record-builder-34 2022-08-02 05:05:14 +02:00
Jordan Zimmerman
6c0fac0dff [maven-release-plugin] rollback the release of record-builder-34 2022-08-02 05:04:43 +02:00
Jordan Zimmerman
ae527cd8e5 [maven-release-plugin] prepare release record-builder-34 2022-08-02 05:04:20 +02:00
Jordan Zimmerman
73ba62057a [maven-release-plugin] rollback the release of record-builder-34 2022-08-02 05:03:00 +02:00
Jordan Zimmerman
87998aba68 [maven-release-plugin] prepare for next development iteration 2022-08-02 05:02:28 +02:00
Jordan Zimmerman
04a0904d3f [maven-release-plugin] prepare release record-builder-34 2022-08-02 05:02:23 +02:00
Johannes
aa072af8e1 Performance feature: copy collections only when they were changed. Fixes #114. (#118) 2022-06-19 21:17:09 +01:00
99 changed files with 2155 additions and 1121 deletions

View File

@@ -21,4 +21,4 @@ jobs:
with: with:
java-version: 16 java-version: 16
- name: Build with Maven - name: Build with Maven
run: mvn -B package --file pom.xml run: ./mvnw -B package --file pom.xml

View File

@@ -21,4 +21,4 @@ jobs:
with: with:
java-version: 17 java-version: 17
- name: Build with Maven - name: Build with Maven
run: mvn -B package --file pom.xml run: ./mvnw -B package --file pom.xml

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
# Default ignored files
.idea
**/target/**

BIN
.mvn/wrapper/maven-wrapper.jar vendored Normal file

Binary file not shown.

18
.mvn/wrapper/maven-wrapper.properties vendored Normal file
View File

@@ -0,0 +1,18 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar

View File

@@ -1,4 +1,4 @@
[![Build Status](https://github.com/Randgalt/record-builder/workflows/Java%20CI%20with%20Maven/badge.svg)](https://github.com/Randgalt/record-builder/actions) [![Maven Build - Java 17](https://github.com/Randgalt/record-builder/actions/workflows/maven_java17.yml/badge.svg)](https://github.com/Randgalt/record-builder/actions/workflows/maven_java17.yml)
[![Maven Central](https://img.shields.io/maven-central/v/io.soabase.record-builder/record-builder.svg?sort=date)](https://search.maven.org/search?q=g:io.soabase.record-builder%20a:record-builder) [![Maven Central](https://img.shields.io/maven-central/v/io.soabase.record-builder/record-builder.svg?sort=date)](https://search.maven.org/search?q=g:io.soabase.record-builder%20a:record-builder)
# RecordBuilder # RecordBuilder

287
mvnw vendored Executable file
View File

@@ -0,0 +1,287 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Apache Maven Wrapper startup batch script, version 3.1.1
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /usr/local/etc/mavenrc ] ; then
. /usr/local/etc/mavenrc
fi
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
JAVA_HOME="`/usr/libexec/java_home`"; export JAVA_HOME
else
JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`\\unset -f command; \\command -v java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
printf '%s' "$(cd "$basedir"; pwd)"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=$(find_maven_basedir "$(dirname $0)")
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
if [ -n "$MVNW_REPOURL" ]; then
wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
else
wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) wrapperUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $wrapperUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
QUIET="--quiet"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
QUIET=""
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget $QUIET "$wrapperUrl" -O "$wrapperJarPath"
else
wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath"
fi
[ $? -eq 0 ] || rm -f "$wrapperJarPath"
elif command -v curl > /dev/null; then
QUIET="--silent"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
QUIET=""
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L
else
curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L
fi
[ $? -eq 0 ] || rm -f "$wrapperJarPath"
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaSource="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaSource=`cygpath --path --windows "$javaSource"`
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaSource" ]; then
if [ ! -e "$javaClass" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaSource")
fi
if [ -e "$javaClass" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
$MAVEN_DEBUG_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

187
mvnw.cmd vendored Normal file
View File

@@ -0,0 +1,187 @@
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM http://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Apache Maven Wrapper startup batch script, version 3.1.1
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %WRAPPER_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% ^
%JVM_CONFIG_MAVEN_PROPS% ^
%MAVEN_OPTS% ^
%MAVEN_DEBUG_OPTS% ^
-classpath %WRAPPER_JAR% ^
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
%WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%"=="on" pause
if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
cmd /C exit /B %ERROR_CODE%

62
pom.xml
View File

@@ -1,11 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2019 The original author or authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>io.soabase.record-builder</groupId> <groupId>io.soabase.record-builder</groupId>
<artifactId>record-builder</artifactId> <artifactId>record-builder</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
<version>34-SNAPSHOT</version> <version>38-SNAPSHOT</version>
<modules> <modules>
<module>record-builder-core</module> <module>record-builder-core</module>
@@ -25,7 +42,7 @@
<maven-source-plugin-version>3.2.0</maven-source-plugin-version> <maven-source-plugin-version>3.2.0</maven-source-plugin-version>
<maven-install-plugin-version>2.5.2</maven-install-plugin-version> <maven-install-plugin-version>2.5.2</maven-install-plugin-version>
<maven-deploy-plugin-version>2.8.2</maven-deploy-plugin-version> <maven-deploy-plugin-version>2.8.2</maven-deploy-plugin-version>
<maven-license-plugin-version>1.9.0</maven-license-plugin-version> <maven-license-plugin-version>4.1</maven-license-plugin-version>
<maven-gpg-plugin-version>1.6</maven-gpg-plugin-version> <maven-gpg-plugin-version>1.6</maven-gpg-plugin-version>
<maven-javadoc-plugin-version>3.1.1</maven-javadoc-plugin-version> <maven-javadoc-plugin-version>3.1.1</maven-javadoc-plugin-version>
<maven-clean-plugin-version>3.1.0</maven-clean-plugin-version> <maven-clean-plugin-version>3.1.0</maven-clean-plugin-version>
@@ -35,11 +52,13 @@
<maven-surefire-plugin-version>3.0.0-M5</maven-surefire-plugin-version> <maven-surefire-plugin-version>3.0.0-M5</maven-surefire-plugin-version>
<jacoco-maven-plugin-version>0.8.7</jacoco-maven-plugin-version> <jacoco-maven-plugin-version>0.8.7</jacoco-maven-plugin-version>
<formatter-maven-plugin-version>2.22.0</formatter-maven-plugin-version>
<license-file-path>src/etc/header.txt</license-file-path> <license-file-path>src/etc/header.txt</license-file-path>
<javapoet-version>1.12.1</javapoet-version> <javapoet-version>1.12.1</javapoet-version>
<junit-jupiter-version>5.5.2</junit-jupiter-version> <junit-jupiter-version>5.5.2</junit-jupiter-version>
<assertj-core.version>3.24.2</assertj-core.version>
<asm-version>7.2</asm-version> <asm-version>7.2</asm-version>
<validation-api-version>2.0.1.Final</validation-api-version> <validation-api-version>2.0.1.Final</validation-api-version>
<hibernate-validator-version>6.0.20.Final</hibernate-validator-version> <hibernate-validator-version>6.0.20.Final</hibernate-validator-version>
@@ -133,6 +152,12 @@
<version>${junit-jupiter-version}</version> <version>${junit-jupiter-version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj-core.version}</version>
</dependency>
<dependency> <dependency>
<groupId>javax.validation</groupId> <groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId> <artifactId>validation-api</artifactId>
@@ -195,8 +220,8 @@
</plugin> </plugin>
<plugin> <plugin>
<groupId>com.mycila.maven-license-plugin</groupId> <groupId>com.mycila</groupId>
<artifactId>maven-license-plugin</artifactId> <artifactId>license-maven-plugin</artifactId>
<version>${maven-license-plugin-version}</version> <version>${maven-license-plugin-version}</version>
<configuration> <configuration>
<header>${license-file-path}</header> <header>${license-file-path}</header>
@@ -227,6 +252,8 @@
<exclude>**/.travis.yml</exclude> <exclude>**/.travis.yml</exclude>
<exclude>**/gradlew</exclude> <exclude>**/gradlew</exclude>
<exclude>**/.github/**</exclude> <exclude>**/.github/**</exclude>
<exclude>**/.mvn/**</exclude>
<exclude>**/mvnw*</exclude>
</excludes> </excludes>
<strictCheck>true</strictCheck> <strictCheck>true</strictCheck>
</configuration> </configuration>
@@ -334,6 +361,24 @@
<artifactId>jacoco-maven-plugin</artifactId> <artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco-maven-plugin-version}</version> <version>${jacoco-maven-plugin-version}</version>
</plugin> </plugin>
<plugin>
<groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<version>${formatter-maven-plugin-version}</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>format</goal>
</goals>
<configuration>
<compilerCompliance>17</compilerCompliance>
<compilerSource>17</compilerSource>
</configuration>
</execution>
</executions>
</plugin>
</plugins> </plugins>
</pluginManagement> </pluginManagement>
@@ -354,8 +399,8 @@
</plugin> </plugin>
<plugin> <plugin>
<groupId>com.mycila.maven-license-plugin</groupId> <groupId>com.mycila</groupId>
<artifactId>maven-license-plugin</artifactId> <artifactId>license-maven-plugin</artifactId>
</plugin> </plugin>
<plugin> <plugin>
@@ -372,6 +417,11 @@
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
</plugin> </plugin>
<plugin>
<groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId>
</plugin>
</plugins> </plugins>
</build> </build>

View File

@@ -1,9 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2019 The original author or authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<groupId>io.soabase.record-builder</groupId> <groupId>io.soabase.record-builder</groupId>
<artifactId>record-builder</artifactId> <artifactId>record-builder</artifactId>
<version>34-SNAPSHOT</version> <version>38-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -15,43 +15,47 @@
*/ */
package io.soabase.recordbuilder.core; package io.soabase.recordbuilder.core;
import java.lang.annotation.*; import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.lang.model.element.Modifier;
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
@Inherited @Inherited
public @interface RecordBuilder { public @interface RecordBuilder {
@Target({ElementType.TYPE, ElementType.PACKAGE}) @Target({ ElementType.TYPE, ElementType.PACKAGE })
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@Inherited @Inherited
@interface Include { @interface Include {
/** /**
* @return list of classes to include * @return collection of classes to include
*/ */
Class<?>[] value() default {}; Class<?>[] value() default {};
/** /**
* Synonym for {@code value()}. When using the other attributes it maybe more clear to * Synonym for {@code value()}. When using the other attributes it maybe clearer to use {@code classes()}
* use {@code classes()} instead of {@code value()}. Note: both attributes are applied * instead of {@code value()}. Note: both attributes are applied (i.e. a union of classes from both attributes).
* (i.e. a union of classes from both attributes).
* *
* @return list of classes * @return collection of classes
*/ */
Class<?>[] classes() default {}; Class<?>[] classes() default {};
/** /**
* Optional list of package names. All records in the packages will get processed as * Optional list of package names. All records in the packages will get processed as if they were listed as
* if they were listed as classes to include. * classes to include.
* *
* @return list of package names * @return collection of package names
*/ */
String[] packages() default {}; String[] packages() default {};
/** /**
* Pattern used to generate the package for the generated class. The value * Pattern used to generate the package for the generated class. The value is the literal package name however
* is the literal package name however two replacement values can be used. '@' * two replacement values can be used. '@' is replaced with the package of the {@code Include} annotation. '*'
* is replaced with the package of the {@code Include} annotation. '*' is replaced with * is replaced with the package of the included class.
* the package of the included class.
* *
* @return package pattern * @return package pattern
*/ */
@@ -59,18 +63,18 @@ public @interface RecordBuilder {
} }
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE) @Target({ ElementType.TYPE, ElementType.PACKAGE })
@Inherited @Inherited
@interface Options { @interface Options {
/** /**
* The builder class name will be the name of the record (prefixed with any enclosing class) plus this suffix. E.g. * The builder class name will be the name of the record (prefixed with any enclosing class) plus this suffix.
* if the record name is "Foo", the builder will be named "FooBuilder". * E.g. if the record name is "Foo", the builder will be named "FooBuilder".
*/ */
String suffix() default "Builder"; String suffix() default "Builder";
/** /**
* Used by {@code RecordInterface}. The generated record will have the same name as the annotated interface * Used by {@code RecordInterface}. The generated record will have the same name as the annotated interface plus
* plus this suffix. E.g. if the interface name is "Foo", the record will be named "FooRecord". * this suffix. E.g. if the interface name is "Foo", the record will be named "FooRecord".
*/ */
String interfaceSuffix() default "Record"; String interfaceSuffix() default "Record";
@@ -125,22 +129,20 @@ public @interface RecordBuilder {
String fileIndent() default " "; String fileIndent() default " ";
/** /**
* If the record is declared inside of another class, the outer class's name will * If the record is declared inside another class, the outer class's name will be prefixed to the builder name
* be prefixed to the builder name if this returns true. * if this returns true.
*/ */
boolean prefixEnclosingClassNames() default true; boolean prefixEnclosingClassNames() default true;
/** /**
* If true, any annotations (if applicable) on record components are copied * If true, any annotations (if applicable) on record components are copied to the builder methods
* to the builder methods
* *
* @return true/false * @return true/false
*/ */
boolean inheritComponentAnnotations() default true; boolean inheritComponentAnnotations() default true;
/** /**
* Set the default value of {@code Optional} record components to * Set the default value of {@code Optional} record components to {@code Optional.empty()}
* {@code Optional.empty()}
*/ */
boolean emptyDefaultForOptional() default true; boolean emptyDefaultForOptional() default true;
@@ -150,8 +152,8 @@ public @interface RecordBuilder {
boolean addConcreteSettersForOptional() default false; boolean addConcreteSettersForOptional() default false;
/** /**
* Add not-null checks for record components annotated with any annotation named either "NotNull", * Add not-null checks for record components annotated with any annotation named either "NotNull", "NoNull", or
* "NoNull", or "NonNull" (see {@link #interpretNotNullsPattern()} for the actual regex matching pattern). * "NonNull" (see {@link #interpretNotNullsPattern()} for the actual regex matching pattern).
*/ */
boolean interpretNotNulls() default false; boolean interpretNotNulls() default false;
@@ -162,29 +164,51 @@ public @interface RecordBuilder {
String interpretNotNullsPattern() default "(?i)((notnull)|(nonnull)|(nonull))"; String interpretNotNullsPattern() default "(?i)((notnull)|(nonnull)|(nonull))";
/** /**
* <p>Pass built records through the Java Validation API if it's available in the classpath.</p> * <p>
* Pass built records through the Java Validation API if it's available in the classpath.
* </p>
* *
* <p>IMPORTANT: * <p>
* if this option is enabled you must include the {@code record-builder-validator} dependency in addition * IMPORTANT: if this option is enabled you must include the {@code record-builder-validator} dependency in
* to {@code record-builder-core}. {@code record-builder-validator} is implemented completely via reflection and * addition to {@code record-builder-core}. {@code record-builder-validator} is implemented completely via
* does not require other dependencies. Alternatively, you can define your own class with the package {@code package io.soabase.recordbuilder.validator;} * reflection and does not require other dependencies. Alternatively, you can define your own class with the
* named {@code RecordBuilderValidator} which has a public static method: {@code public static <T> T validate(T o)}.</p> * package {@code package io.soabase.recordbuilder.validator;} named {@code RecordBuilderValidator} which has a
* public static method: {@code public static <T> T validate(T o)}.
* </p>
*/ */
boolean useValidationApi() default false; boolean useValidationApi() default false;
/** /**
* Adds special handling for record components of type {@link java.util.List}, {@link java.util.Set}, * Adds special handling for record components of type {@link java.util.List}, {@link java.util.Set},
* {@link java.util.Map} and {@link java.util.Collection}. When the record is built, any components * {@link java.util.Map} and {@link java.util.Collection}. When the record is built, any components of these
* of these types are passed through an added shim method that uses the corresponding immutable collection * types are passed through an added shim method that uses the corresponding immutable collection (e.g.
* (e.g. {@code List.copyOf(o)}) or an empty immutable collection if the component is {@code null}. * {@code List.copyOf(o)}) or an empty immutable collection if the component is {@code null}.
*
* @see #useUnmodifiableCollections()
*/ */
boolean useImmutableCollections() default false; boolean useImmutableCollections() default false;
/** /**
* When enabled, collection types ({@code List}, {@code Set} and {@code Map}) are handled specially. * Adds special handling for record components of type: {@link java.util.List}, {@link java.util.Set},
* The setters for these types now create an internal collection and items are added to that * {@link java.util.Map} and {@link java.util.Collection}. When the record is built, any components of these
* collection. Additionally, "adder" methods prefixed with {@link #singleItemBuilderPrefix()} are created * types are passed through an added shim method that uses the corresponding unmodifiable collection (e.g.
* to add single items to these collections. * {@code Collections.unmodifiableList(o)}) or an empty immutable collection if the component is {@code null}.
*
* <p>
* For backward compatibility, when {@link #useImmutableCollections()} returns {@code true}, this property is
* ignored.
*
* @see #useImmutableCollections()
*
* @since 37
*/
boolean useUnmodifiableCollections() default false;
/**
* When enabled, collection types ({@code List}, {@code Set} and {@code Map}) are handled specially. The setters
* for these types now create an internal collection and items are added to that collection. Additionally,
* "adder" methods prefixed with {@link #singleItemBuilderPrefix()} are created to add single items to these
* collections.
*/ */
boolean addSingleItemCollectionBuilders() default false; boolean addSingleItemCollectionBuilders() default false;
@@ -194,14 +218,14 @@ public @interface RecordBuilder {
String singleItemBuilderPrefix() default "add"; String singleItemBuilderPrefix() default "add";
/** /**
* When enabled, adds functional methods to the nested "With" class (such as {@code map()} and {@code accept()}). * When enabled, adds functional methods to the nested "With" class (such as {@code map()} and
* {@code accept()}).
*/ */
boolean addFunctionalMethodsToWith() default false; boolean addFunctionalMethodsToWith() default false;
/** /**
* If set, all builder setter methods will be prefixed with this string. Camel-casing will * If set, all builder setter methods will be prefixed with this string. Camel-casing will still be enforced, so
* still be enforced, so if this option is set to "set" a field named "myField" will get * if this option is set to "set" a field named "myField" will get a corresponding setter named "setMyField".
* a corresponding setter named "setMyField".
*/ */
String setterPrefix() default ""; String setterPrefix() default "";
@@ -211,47 +235,67 @@ public @interface RecordBuilder {
boolean enableGetters() default true; boolean enableGetters() default true;
/** /**
* If set, all builder getter methods will be prefixed with this string. Camel-casing will * If set, all builder getter methods will be prefixed with this string. Camel-casing will still be enforced, so
* still be enforced, so if this option is set to "get", a field named "myField" will get * if this option is set to "get", a field named "myField" will get a corresponding getter named "getMyField".
* a corresponding getter named "getMyField".
*/ */
String getterPrefix() default ""; String getterPrefix() default "";
/** /**
* If set, all boolean builder getter methods will be prefixed with this string. * If set, all boolean builder getter methods will be prefixed with this string. Camel-casing will still be
* Camel-casing will still be enforced, so if this option is set to "is", a field named * enforced, so if this option is set to "is", a field named "myField" will get a corresponding getter named
* "myField" will get a corresponding getter named "isMyField". * "isMyField".
*/ */
String booleanPrefix() default ""; String booleanPrefix() default "";
/** /**
* If set, the Builder will contain an internal interface with this name. This interface * If set, the Builder will contain an internal interface with this name. This interface contains getters for
* contains getters for all the fields in the Record prefixed with the value supplied in * all the fields in the Record prefixed with the value supplied in {@link this.getterPrefix} and
* {@link this.getterPrefix} and {@link this.booleanPrefix}. This interface can be * {@link this.booleanPrefix}. This interface can be implemented by the original Record to have proper
* implemented by the original Record to have proper bean-style prefixed getters. * bean-style prefixed getters. Please note that unless either of the aforementioned prefixes are set, this
* * option does nothing.
* Please note that unless either of the aforementioned prefixes are set,
* this option does nothing.
*/ */
String beanClassName() default ""; String beanClassName() default "";
/** /**
* If true, generated classes are annotated with {@code RecordBuilderGenerated} which has a retention * If true, generated classes are annotated with {@code RecordBuilderGenerated} which has a retention policy of
* policy of {@code CLASS}. This ensures that analyzers such as Jacoco will ignore the generated class. * {@code CLASS}. This ensures that analyzers such as Jacoco will ignore the generated class.
*/ */
boolean addClassRetainedGenerated() default false; boolean addClassRetainedGenerated() default false;
/** /**
* The {@link #fromMethodName} method instantiates an internal private class. This is the * The {@link #fromMethodName} method instantiates an internal private class. This is the name of that class.
* name of that class.
*/ */
String fromWithClassName() default "_FromWith"; String fromWithClassName() default "_FromWith";
/** /**
* If true, a functional-style builder is added so that record instances can be instantiated * If true, a functional-style builder is added so that record instances can be instantiated without
* without {@code new}. * {@code new}.
*/ */
boolean addStaticBuilder() default true; boolean addStaticBuilder() default true;
/**
* If {@link #addSingleItemCollectionBuilders()} and {@link #useImmutableCollections()} are enabled the builder
* uses an internal class to track changes to lists. This is the name of that class.
*/
String mutableListClassName() default "_MutableList";
/**
* If {@link #addSingleItemCollectionBuilders()} and {@link #useImmutableCollections()} are enabled the builder
* uses an internal class to track changes to sets. This is the name of that class.
*/
String mutableSetClassName() default "_MutableSet";
/**
* If {@link #addSingleItemCollectionBuilders()} and {@link #useImmutableCollections()} are enabled the builder
* uses an internal class to track changes to maps. This is the name of that class.
*/
String mutableMapClassName() default "_MutableMap";
/**
* Any additional {@link javax.lang.model.element.Modifier} you wish to apply to the builder. For example to
* make the builder public when the record is package protect.
*/
Modifier[] builderClassModifiers() default {};
} }
@Retention(RetentionPolicy.CLASS) @Retention(RetentionPolicy.CLASS)

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,19 +17,12 @@ package io.soabase.recordbuilder.core;
import java.lang.annotation.*; import java.lang.annotation.*;
@RecordBuilder.Template(options = @RecordBuilder.Options( /**
interpretNotNulls = true, * An alternate form of {@code @RecordBuilder} that has most optional features turned on
useImmutableCollections = true, */
addSingleItemCollectionBuilders = true, @RecordBuilder.Template(options = @RecordBuilder.Options(interpretNotNulls = true, useImmutableCollections = true, addSingleItemCollectionBuilders = true, addFunctionalMethodsToWith = true, addClassRetainedGenerated = true))
addFunctionalMethodsToWith = true,
addClassRetainedGenerated = true
))
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
@Inherited @Inherited
/**
* An alternate form of {@code @RecordBuilder} that has most
* optional features turned on
*/
public @interface RecordBuilderFull { public @interface RecordBuilderFull {
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@ import static java.lang.annotation.ElementType.*;
/** /**
* Jacoco ignores classes and methods annotated with `*Generated` * Jacoco ignores classes and methods annotated with `*Generated`
*/ */
@Target({PACKAGE, TYPE, METHOD, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, PARAMETER}) @Target({ PACKAGE, TYPE, METHOD, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, PARAMETER })
@Retention(RetentionPolicy.CLASS) @Retention(RetentionPolicy.CLASS)
public @interface RecordBuilderGenerated { public @interface RecordBuilderGenerated {
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -23,21 +23,20 @@ import java.lang.annotation.*;
public @interface RecordInterface { public @interface RecordInterface {
boolean addRecordBuilder() default true; boolean addRecordBuilder() default true;
@Target({ElementType.TYPE, ElementType.PACKAGE}) @Target({ ElementType.TYPE, ElementType.PACKAGE })
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@Inherited @Inherited
@interface Include { @interface Include {
/** /**
* @return list of classes to include * @return collection of classes to include
*/ */
Class<?>[] value() default {}; Class<?>[] value() default {};
/** /**
* Synonym for {@code value()}. When using the other attributes it maybe more clear to * Synonym for {@code value()}. When using the other attributes it maybe clearer to use {@code classes()}
* use {@code classes()} instead of {@code value()}. Note: both attributes are applied * instead of {@code value()}. Note: both attributes are applied (i.e. a union of classes from both attributes).
* (i.e. a union of classes from both attributes).
* *
* @return list of classes * @return collection of classes
*/ */
Class<?>[] classes() default {}; Class<?>[] classes() default {};
@@ -49,10 +48,9 @@ public @interface RecordInterface {
boolean addRecordBuilder() default true; boolean addRecordBuilder() default true;
/** /**
* Pattern used to generate the package for the generated class. The value * Pattern used to generate the package for the generated class. The value is the literal package name however
* is the literal package name however two replacement values can be used. '@' * two replacement values can be used. '@' is replaced with the package of the {@code Include} annotation. '*'
* is replaced with the package of the {@code Include} annotation. '*' is replaced with * is replaced with the package of the included class.
* the package of the included class.
* *
* @return package pattern * @return package pattern
*/ */

View File

@@ -1,9 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2019 The original author or authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<groupId>io.soabase.record-builder</groupId> <groupId>io.soabase.record-builder</groupId>
<artifactId>record-builder</artifactId> <artifactId>record-builder</artifactId>
<version>34-SNAPSHOT</version> <version>38-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -22,87 +22,135 @@ import javax.lang.model.element.Modifier;
import java.util.*; import java.util.*;
import static io.soabase.recordbuilder.processor.RecordBuilderProcessor.generatedRecordBuilderAnnotation; import static io.soabase.recordbuilder.processor.RecordBuilderProcessor.generatedRecordBuilderAnnotation;
import static io.soabase.recordbuilder.processor.RecordBuilderProcessor.recordBuilderGeneratedAnnotation;
class CollectionBuilderUtils { class CollectionBuilderUtils {
private final boolean useImmutableCollections; private final boolean useImmutableCollections;
private final boolean useUnmodifiableCollections;
private final boolean addSingleItemCollectionBuilders; private final boolean addSingleItemCollectionBuilders;
private final boolean addClassRetainedGenerated;
private final String listShimName; private final String listShimName;
private final String mapShimName; private final String mapShimName;
private final String setShimName; private final String setShimName;
private final String collectionShimName; private final String collectionShimName;
private final String listMakerMethodName;
private final String mapMakerMethodName;
private final String setMakerMethodName;
private boolean needsListShim; private boolean needsListShim;
private boolean needsMapShim; private boolean needsMapShim;
private boolean needsSetShim; private boolean needsSetShim;
private boolean needsCollectionShim; private boolean needsCollectionShim;
private static final TypeName listType = TypeName.get(List.class); private boolean needsListMutableMaker;
private static final TypeName mapType = TypeName.get(Map.class); private boolean needsMapMutableMaker;
private static final TypeName setType = TypeName.get(Set.class); private boolean needsSetMutableMaker;
private static final TypeName collectionType = TypeName.get(Collection.class);
private static final Class<?> listType = List.class;
private static final Class<?> mapType = Map.class;
private static final Class<?> setType = Set.class;
private static final Class<?> collectionType = Collection.class;
private static final Class<?> collectionsType = Collections.class;
private static final TypeName listTypeName = TypeName.get(listType);
private static final TypeName mapTypeName = TypeName.get(mapType);
private static final TypeName setTypeName = TypeName.get(setType);
private static final TypeName collectionTypeName = TypeName.get(collectionType);
private static final TypeName collectionsTypeName = TypeName.get(collectionsType);
private static final TypeVariableName tType = TypeVariableName.get("T"); private static final TypeVariableName tType = TypeVariableName.get("T");
private static final TypeVariableName kType = TypeVariableName.get("K"); private static final TypeVariableName kType = TypeVariableName.get("K");
private static final TypeVariableName vType = TypeVariableName.get("V"); private static final TypeVariableName vType = TypeVariableName.get("V");
private static final ParameterizedTypeName parameterizedListType = ParameterizedTypeName.get(ClassName.get(List.class), tType); private static final ParameterizedTypeName parameterizedListType = ParameterizedTypeName
private static final ParameterizedTypeName parameterizedMapType = ParameterizedTypeName.get(ClassName.get(Map.class), kType, vType); .get(ClassName.get(List.class), tType);
private static final ParameterizedTypeName parameterizedSetType = ParameterizedTypeName.get(ClassName.get(Set.class), tType); private static final ParameterizedTypeName parameterizedMapType = ParameterizedTypeName
private static final ParameterizedTypeName parameterizedCollectionType = ParameterizedTypeName.get(ClassName.get(Collection.class), tType); .get(ClassName.get(Map.class), kType, vType);
private static final ParameterizedTypeName parameterizedSetType = ParameterizedTypeName
.get(ClassName.get(Set.class), tType);
private static final ParameterizedTypeName parameterizedCollectionType = ParameterizedTypeName
.get(ClassName.get(Collection.class), tType);
private static final Class<?> mutableListType = ArrayList.class;
private static final Class<?> mutableMapType = HashMap.class;
private static final Class<?> mutableSetType = HashSet.class;
private static final ClassName mutableListTypeName = ClassName.get(mutableListType);
private static final ClassName mutableMapTypeName = ClassName.get(mutableMapType);
private static final ClassName mutableSetTypeName = ClassName.get(mutableSetType);
private final TypeSpec mutableListSpec;
private final TypeSpec mutableSetSpec;
private final TypeSpec mutableMapSpec;
CollectionBuilderUtils(List<RecordClassType> recordComponents, RecordBuilder.Options metaData) { CollectionBuilderUtils(List<RecordClassType> recordComponents, RecordBuilder.Options metaData) {
useImmutableCollections = metaData.useImmutableCollections(); useImmutableCollections = metaData.useImmutableCollections();
useUnmodifiableCollections = !useImmutableCollections && metaData.useUnmodifiableCollections();
addSingleItemCollectionBuilders = metaData.addSingleItemCollectionBuilders(); addSingleItemCollectionBuilders = metaData.addSingleItemCollectionBuilders();
addClassRetainedGenerated = metaData.addClassRetainedGenerated();
listShimName = adjustShimName(recordComponents, "__list", 0); listShimName = disambiguateGeneratedMethodName(recordComponents, "__list", 0);
mapShimName = adjustShimName(recordComponents, "__map", 0); mapShimName = disambiguateGeneratedMethodName(recordComponents, "__map", 0);
setShimName = adjustShimName(recordComponents, "__set", 0); setShimName = disambiguateGeneratedMethodName(recordComponents, "__set", 0);
collectionShimName = adjustShimName(recordComponents, "__collection", 0); collectionShimName = disambiguateGeneratedMethodName(recordComponents, "__collection", 0);
listMakerMethodName = disambiguateGeneratedMethodName(recordComponents, "__ensureListMutable", 0);
setMakerMethodName = disambiguateGeneratedMethodName(recordComponents, "__ensureSetMutable", 0);
mapMakerMethodName = disambiguateGeneratedMethodName(recordComponents, "__ensureMapMutable", 0);
mutableListSpec = buildMutableCollectionSubType(metaData.mutableListClassName(), mutableListTypeName,
parameterizedListType, tType);
mutableSetSpec = buildMutableCollectionSubType(metaData.mutableSetClassName(), mutableSetTypeName,
parameterizedSetType, tType);
mutableMapSpec = buildMutableCollectionSubType(metaData.mutableMapClassName(), mutableMapTypeName,
parameterizedMapType, kType, vType);
} }
enum SingleItemsMetaDataMode { enum SingleItemsMetaDataMode {
STANDARD, STANDARD, STANDARD_FOR_SETTER, EXCLUDE_WILDCARD_TYPES
STANDARD_FOR_SETTER,
EXCLUDE_WILDCARD_TYPES
} }
record SingleItemsMetaData(Class<?> singleItemCollectionClass, List<TypeName> typeArguments, TypeName wildType) {} record SingleItemsMetaData(Class<?> singleItemCollectionClass, List<TypeName> typeArguments, TypeName wildType) {
}
Optional<SingleItemsMetaData> singleItemsMetaData(RecordClassType component, SingleItemsMetaDataMode mode) { Optional<SingleItemsMetaData> singleItemsMetaData(RecordClassType component, SingleItemsMetaDataMode mode) {
if (addSingleItemCollectionBuilders && (component.typeName() instanceof ParameterizedTypeName parameterizedTypeName)) { if (addSingleItemCollectionBuilders
&& (component.typeName() instanceof ParameterizedTypeName parameterizedTypeName)) {
Class<?> collectionClass = null; Class<?> collectionClass = null;
ClassName wildcardClass = null; ClassName wildcardClass = null;
int typeArgumentQty = 0; int typeArgumentQty = 0;
if (isList(component)) { if (isList(component)) {
collectionClass = ArrayList.class; collectionClass = mutableListType;
wildcardClass = ClassName.get(Collection.class); wildcardClass = ClassName.get(Collection.class);
typeArgumentQty = 1; typeArgumentQty = 1;
} else if (isSet(component)) { } else if (isSet(component)) {
collectionClass = HashSet.class; collectionClass = mutableSetType;
wildcardClass = ClassName.get(Collection.class); wildcardClass = ClassName.get(Collection.class);
typeArgumentQty = 1; typeArgumentQty = 1;
} else if (isMap(component)) { } else if (isMap(component)) {
collectionClass = HashMap.class; collectionClass = mutableMapType;
wildcardClass = (ClassName) component.rawTypeName(); wildcardClass = (ClassName) component.rawTypeName();
typeArgumentQty = 2; typeArgumentQty = 2;
} }
var hasWildcardTypeArguments = hasWildcardTypeArguments(parameterizedTypeName, typeArgumentQty); var hasWildcardTypeArguments = hasWildcardTypeArguments(parameterizedTypeName, typeArgumentQty);
if (collectionClass != null) { if (collectionClass != null) {
return switch (mode) { return switch (mode) {
case STANDARD -> singleItemsMetaDataWithWildType(parameterizedTypeName, collectionClass, wildcardClass, typeArgumentQty); case STANDARD -> singleItemsMetaDataWithWildType(parameterizedTypeName, collectionClass, wildcardClass,
typeArgumentQty);
case STANDARD_FOR_SETTER -> { case STANDARD_FOR_SETTER -> {
if (hasWildcardTypeArguments) { if (hasWildcardTypeArguments) {
yield Optional.of(new SingleItemsMetaData(collectionClass, parameterizedTypeName.typeArguments, component.typeName())); yield Optional.of(new SingleItemsMetaData(collectionClass, parameterizedTypeName.typeArguments,
} component.typeName()));
yield singleItemsMetaDataWithWildType(parameterizedTypeName, collectionClass, wildcardClass, typeArgumentQty);
} }
yield singleItemsMetaDataWithWildType(parameterizedTypeName, collectionClass, wildcardClass,
typeArgumentQty);
}
case EXCLUDE_WILDCARD_TYPES -> { case EXCLUDE_WILDCARD_TYPES -> {
if (hasWildcardTypeArguments) { if (hasWildcardTypeArguments) {
yield Optional.empty(); yield Optional.empty();
}
yield singleItemsMetaDataWithWildType(parameterizedTypeName, collectionClass, wildcardClass, typeArgumentQty);
} }
yield singleItemsMetaDataWithWildType(parameterizedTypeName, collectionClass, wildcardClass,
typeArgumentQty);
}
}; };
} }
} }
@@ -110,33 +158,41 @@ class CollectionBuilderUtils {
} }
boolean isImmutableCollection(RecordClassType component) { boolean isImmutableCollection(RecordClassType component) {
return useImmutableCollections && (isList(component) || isMap(component) || isSet(component) || component.rawTypeName().equals(collectionType)); return (useImmutableCollections || useUnmodifiableCollections)
&& (isList(component) || isMap(component) || isSet(component) || isCollection(component));
} }
boolean isList(RecordClassType component) { boolean isList(RecordClassType component) {
return component.rawTypeName().equals(listType); return component.rawTypeName().equals(listTypeName);
} }
boolean isMap(RecordClassType component) { boolean isMap(RecordClassType component) {
return component.rawTypeName().equals(mapType); return component.rawTypeName().equals(mapTypeName);
} }
boolean isSet(RecordClassType component) { boolean isSet(RecordClassType component) {
return component.rawTypeName().equals(setType); return component.rawTypeName().equals(setTypeName);
} }
void add(CodeBlock.Builder builder, RecordClassType component) { private boolean isCollection(RecordClassType component) {
if (useImmutableCollections) { return component.rawTypeName().equals(collectionTypeName);
}
void addShimCall(CodeBlock.Builder builder, RecordClassType component) {
if (useImmutableCollections || useUnmodifiableCollections) {
if (isList(component)) { if (isList(component)) {
needsListShim = true; needsListShim = true;
needsListMutableMaker = true;
builder.add("$L($L)", listShimName, component.name()); builder.add("$L($L)", listShimName, component.name());
} else if (isMap(component)) { } else if (isMap(component)) {
needsMapShim = true; needsMapShim = true;
needsMapMutableMaker = true;
builder.add("$L($L)", mapShimName, component.name()); builder.add("$L($L)", mapShimName, component.name());
} else if (isSet(component)) { } else if (isSet(component)) {
needsSetShim = true; needsSetShim = true;
needsSetMutableMaker = true;
builder.add("$L($L)", setShimName, component.name()); builder.add("$L($L)", setShimName, component.name());
} else if (component.rawTypeName().equals(collectionType)) { } else if (isCollection(component)) {
needsCollectionShim = true; needsCollectionShim = true;
builder.add("$L($L)", collectionShimName, component.name()); builder.add("$L($L)", collectionShimName, component.name());
} else { } else {
@@ -147,31 +203,84 @@ class CollectionBuilderUtils {
} }
} }
String shimName(RecordClassType component) {
if (isList(component)) {
return listShimName;
} else if (isMap(component)) {
return mapShimName;
} else if (isSet(component)) {
return setShimName;
} else if (isCollection(component)) {
return collectionShimName;
} else {
throw new IllegalArgumentException(component + " is not a supported collection type");
}
}
String mutableMakerName(RecordClassType component) {
if (isList(component)) {
return listMakerMethodName;
} else if (isMap(component)) {
return mapMakerMethodName;
} else if (isSet(component)) {
return setMakerMethodName;
} else {
throw new IllegalArgumentException(component + " is not a supported collection type");
}
}
void addShims(TypeSpec.Builder builder) { void addShims(TypeSpec.Builder builder) {
if (!useImmutableCollections) { if (!useImmutableCollections && !useUnmodifiableCollections) {
return; return;
} }
if (needsListShim) { if (needsListShim) {
builder.addMethod(buildMethod(listShimName, listType, parameterizedListType, tType)); builder.addMethod(
buildShimMethod(listShimName, listTypeName, collectionType, parameterizedListType, tType));
} }
if (needsSetShim) { if (needsSetShim) {
builder.addMethod(buildMethod(setShimName, setType, parameterizedSetType, tType)); builder.addMethod(buildShimMethod(setShimName, setTypeName, collectionType, parameterizedSetType, tType));
} }
if (needsMapShim) { if (needsMapShim) {
builder.addMethod(buildMethod(mapShimName, mapType, parameterizedMapType, kType, vType)); builder.addMethod(buildShimMethod(mapShimName, mapTypeName, mapType, parameterizedMapType, kType, vType));
} }
if (needsCollectionShim) { if (needsCollectionShim) {
builder.addMethod(buildCollectionsMethod()); builder.addMethod(buildCollectionsShimMethod());
} }
} }
private Optional<SingleItemsMetaData> singleItemsMetaDataWithWildType(ParameterizedTypeName parameterizedTypeName, Class<?> collectionClass, ClassName wildcardClass, int typeArgumentQty) { void addMutableMakers(TypeSpec.Builder builder) {
if (!useImmutableCollections && !useUnmodifiableCollections) {
return;
}
if (needsListMutableMaker) {
builder.addMethod(
buildMutableMakerMethod(listMakerMethodName, mutableListSpec.name, parameterizedListType, tType));
builder.addType(mutableListSpec);
}
if (needsSetMutableMaker) {
builder.addMethod(
buildMutableMakerMethod(setMakerMethodName, mutableSetSpec.name, parameterizedSetType, tType));
builder.addType(mutableSetSpec);
}
if (needsMapMutableMaker) {
builder.addMethod(buildMutableMakerMethod(mapMakerMethodName, mutableMapSpec.name, parameterizedMapType,
kType, vType));
builder.addType(mutableMapSpec);
}
}
private Optional<SingleItemsMetaData> singleItemsMetaDataWithWildType(ParameterizedTypeName parameterizedTypeName,
Class<?> collectionClass, ClassName wildcardClass, int typeArgumentQty) {
TypeName wildType; TypeName wildType;
if (typeArgumentQty == 1) { if (typeArgumentQty == 1) {
wildType = ParameterizedTypeName.get(wildcardClass, WildcardTypeName.subtypeOf(parameterizedTypeName.typeArguments.get(0))); wildType = ParameterizedTypeName.get(wildcardClass,
WildcardTypeName.subtypeOf(parameterizedTypeName.typeArguments.get(0)));
} else { // if (typeArgumentQty == 2) } else { // if (typeArgumentQty == 2)
wildType = ParameterizedTypeName.get(wildcardClass, WildcardTypeName.subtypeOf(parameterizedTypeName.typeArguments.get(0)), WildcardTypeName.subtypeOf(parameterizedTypeName.typeArguments.get(1))); wildType = ParameterizedTypeName.get(wildcardClass,
WildcardTypeName.subtypeOf(parameterizedTypeName.typeArguments.get(0)),
WildcardTypeName.subtypeOf(parameterizedTypeName.typeArguments.get(1)));
} }
return Optional.of(new SingleItemsMetaData(collectionClass, parameterizedTypeName.typeArguments, wildType)); return Optional.of(new SingleItemsMetaData(collectionClass, parameterizedTypeName.typeArguments, wildType));
} }
@@ -187,42 +296,101 @@ class CollectionBuilderUtils {
return false; return false;
} }
private String adjustShimName(List<RecordClassType> recordComponents, String baseName, int index) { private String disambiguateGeneratedMethodName(List<RecordClassType> recordComponents, String baseName, int index) {
var name = (index == 0) ? baseName : (baseName + index); var name = (index == 0) ? baseName : (baseName + index);
if (recordComponents.stream().anyMatch(component -> component.name().equals(name))) { if (recordComponents.stream().anyMatch(component -> component.name().equals(name))) {
return adjustShimName(recordComponents, baseName, index + 1); return disambiguateGeneratedMethodName(recordComponents, baseName, index + 1);
} }
return name; return name;
} }
private MethodSpec buildMethod(String name, TypeName mainType, ParameterizedTypeName parameterizedType, TypeVariableName... typeVariables) { private MethodSpec buildShimMethod(String name, TypeName mainType, Class<?> abstractType,
var code = CodeBlock.of("return (o != null) ? $T.copyOf(o) : $T.of()", mainType, mainType); ParameterizedTypeName parameterizedType, TypeVariableName... typeVariables) {
return MethodSpec.methodBuilder(name) var code = buildShimMethodBody(mainType, parameterizedType);
.addAnnotation(generatedRecordBuilderAnnotation)
TypeName[] wildCardTypeArguments = parameterizedType.typeArguments.stream().map(WildcardTypeName::subtypeOf)
.toList().toArray(new TypeName[0]);
var extendedParameterizedType = ParameterizedTypeName.get(ClassName.get(abstractType), wildCardTypeArguments);
return MethodSpec.methodBuilder(name).addAnnotation(generatedRecordBuilderAnnotation)
.addModifiers(Modifier.PRIVATE, Modifier.STATIC).addTypeVariables(Arrays.asList(typeVariables))
.returns(parameterizedType).addParameter(extendedParameterizedType, "o").addStatement(code).build();
}
private CodeBlock buildShimMethodBody(TypeName mainType, ParameterizedTypeName parameterizedType) {
if (!useUnmodifiableCollections) {
return CodeBlock.of("return (o != null) ? $T.copyOf(o) : $T.of()", mainType, mainType);
}
if (mainType.equals(listTypeName)) {
return CodeBlock.of("return (o != null) ? $T.<$T>unmodifiableList(($T) o) : $T.<$T>emptyList()",
collectionsTypeName, tType, parameterizedType, collectionsTypeName, tType);
}
if (mainType.equals(setTypeName)) {
return CodeBlock.of("return (o != null) ? $T.<$T>unmodifiableSet(($T) o) : $T.<$T>emptySet()",
collectionsTypeName, tType, parameterizedType, collectionsTypeName, tType);
}
if (mainType.equals(mapTypeName)) {
return CodeBlock.of("return (o != null) ? $T.<$T, $T>unmodifiableMap(($T) o) : $T.<$T, $T>emptyMap()",
collectionsTypeName, kType, vType, parameterizedType, collectionsTypeName, kType, vType);
}
throw new IllegalStateException("Cannot build shim method for" + mainType);
}
private MethodSpec buildMutableMakerMethod(String name, String mutableCollectionType,
ParameterizedTypeName parameterizedType, TypeVariableName... typeVariables) {
var nullCase = CodeBlock.of("if (o == null) return new $L<>()", mutableCollectionType);
var isMutableCase = CodeBlock.of("if (o instanceof $L) return o", mutableCollectionType);
var defaultCase = CodeBlock.of("return new $L<>(o)", mutableCollectionType);
return MethodSpec.methodBuilder(name).addAnnotation(generatedRecordBuilderAnnotation)
.addModifiers(Modifier.PRIVATE, Modifier.STATIC).addTypeVariables(Arrays.asList(typeVariables))
.returns(parameterizedType).addParameter(parameterizedType, "o").addStatement(nullCase)
.addStatement(isMutableCase).addStatement(defaultCase).build();
}
private TypeSpec buildMutableCollectionSubType(String className, ClassName mutableCollectionType,
ParameterizedTypeName parameterizedType, TypeVariableName... typeVariables) {
TypeName[] typeArguments = new TypeName[] {};
typeArguments = Arrays.stream(typeVariables).toList().toArray(typeArguments);
TypeSpec.Builder builder = TypeSpec.classBuilder(className).addAnnotation(generatedRecordBuilderAnnotation)
.addModifiers(Modifier.PRIVATE, Modifier.STATIC) .addModifiers(Modifier.PRIVATE, Modifier.STATIC)
.superclass(ParameterizedTypeName.get(mutableCollectionType, typeArguments))
.addTypeVariables(Arrays.asList(typeVariables)) .addTypeVariables(Arrays.asList(typeVariables))
.returns(parameterizedType) .addMethod(MethodSpec.constructorBuilder().addAnnotation(generatedRecordBuilderAnnotation)
.addParameter(parameterizedType, "o") .addStatement("super()").build())
.addStatement(code) .addMethod(MethodSpec.constructorBuilder().addAnnotation(generatedRecordBuilderAnnotation)
.addParameter(parameterizedType, "o").addStatement("super(o)").build());
if (addClassRetainedGenerated) {
builder.addAnnotation(recordBuilderGeneratedAnnotation);
}
return builder.build();
}
private MethodSpec buildCollectionsShimMethod() {
var code = buildCollectionShimMethodBody();
return MethodSpec.methodBuilder(collectionShimName).addAnnotation(generatedRecordBuilderAnnotation)
.addModifiers(Modifier.PRIVATE, Modifier.STATIC).addTypeVariable(tType)
.returns(parameterizedCollectionType).addParameter(parameterizedCollectionType, "o").addCode(code)
.build(); .build();
} }
private MethodSpec buildCollectionsMethod() { private CodeBlock buildCollectionShimMethodBody() {
var code = CodeBlock.builder() if (!useUnmodifiableCollections) {
.add("if (o instanceof Set) {\n") return CodeBlock.builder().add("if (o instanceof Set) {\n").indent()
.indent() .addStatement("return $T.copyOf(o)", setTypeName).unindent().addStatement("}")
.addStatement("return $T.copyOf(o)", setType) .addStatement("return (o != null) ? $T.copyOf(o) : $T.of()", listTypeName, listTypeName).build();
.unindent() }
.addStatement("}")
.addStatement("return (o != null) ? $T.copyOf(o) : $T.of()", listType, listType) return CodeBlock.builder().beginControlFlow("if (o instanceof $T)", listType)
.build(); .addStatement("return $T.<$T>unmodifiableList(($T) o)", collectionsTypeName, tType,
return MethodSpec.methodBuilder(collectionShimName) parameterizedListType)
.addAnnotation(generatedRecordBuilderAnnotation) .endControlFlow().beginControlFlow("if (o instanceof $T)", setType)
.addModifiers(Modifier.PRIVATE, Modifier.STATIC) .addStatement("return $T.<$T>unmodifiableSet(($T) o)", collectionsTypeName, tType, parameterizedSetType)
.addTypeVariable(tType) .endControlFlow().addStatement("return $T.<$T>emptyList()", collectionsTypeName, tType).build();
.returns(parameterizedCollectionType)
.addParameter(parameterizedCollectionType, "o")
.addCode(code)
.build();
} }
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -37,49 +37,43 @@ import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class ElementUtils { public class ElementUtils {
public static Optional<? extends AnnotationMirror> findAnnotationMirror(ProcessingEnvironment processingEnv, Element element, String annotationClass) { public static Optional<? extends AnnotationMirror> findAnnotationMirror(ProcessingEnvironment processingEnv,
Element element, String annotationClass) {
return processingEnv.getElementUtils().getAllAnnotationMirrors(element).stream() return processingEnv.getElementUtils().getAllAnnotationMirrors(element).stream()
.filter(e -> e.getAnnotationType().toString().equals(annotationClass)) .filter(e -> e.getAnnotationType().toString().equals(annotationClass)).findFirst();
.findFirst();
} }
public static Optional<? extends AnnotationValue> getAnnotationValue(Map<? extends ExecutableElement, ? extends AnnotationValue> values, String name) { public static Optional<? extends AnnotationValue> getAnnotationValue(
return values.entrySet() Map<? extends ExecutableElement, ? extends AnnotationValue> values, String name) {
.stream() return values.entrySet().stream().filter(e -> e.getKey().getSimpleName().toString().equals(name))
.filter(e -> e.getKey().getSimpleName().toString().equals(name)) .map(Map.Entry::getValue).findFirst();
.map(Map.Entry::getValue)
.findFirst();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static List<TypeMirror> getAttributeTypeMirrorList(AnnotationValue attribute) public static List<TypeMirror> getAttributeTypeMirrorList(AnnotationValue attribute) {
{ List<? extends AnnotationValue> values = (attribute != null)
List<? extends AnnotationValue> values = (attribute != null) ? (List<? extends AnnotationValue>)attribute.getValue() : Collections.emptyList(); ? (List<? extends AnnotationValue>) attribute.getValue() : Collections.emptyList();
return values.stream().map(v -> (TypeMirror)v.getValue()).collect(Collectors.toList()); return values.stream().map(v -> (TypeMirror) v.getValue()).collect(Collectors.toList());
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static List<String> getAttributeStringList(AnnotationValue attribute) public static List<String> getAttributeStringList(AnnotationValue attribute) {
{ List<? extends AnnotationValue> values = (attribute != null)
List<? extends AnnotationValue> values = (attribute != null) ? (List<? extends AnnotationValue>)attribute.getValue() : Collections.emptyList(); ? (List<? extends AnnotationValue>) attribute.getValue() : Collections.emptyList();
return values.stream().map(v -> (String)v.getValue()).collect(Collectors.toList()); return values.stream().map(v -> (String) v.getValue()).collect(Collectors.toList());
} }
public static boolean getBooleanAttribute(AnnotationValue attribute) public static boolean getBooleanAttribute(AnnotationValue attribute) {
{
Object value = (attribute != null) ? attribute.getValue() : null; Object value = (attribute != null) ? attribute.getValue() : null;
if ( value != null ) if (value != null) {
{
return Boolean.parseBoolean(String.valueOf(value)); return Boolean.parseBoolean(String.valueOf(value));
} }
return false; return false;
} }
public static String getStringAttribute(AnnotationValue attribute, String defaultValue) public static String getStringAttribute(AnnotationValue attribute, String defaultValue) {
{
Object value = (attribute != null) ? attribute.getValue() : null; Object value = (attribute != null) ? attribute.getValue() : null;
if ( value != null ) if (value != null) {
{
return String.valueOf(value); return String.valueOf(value);
} }
return defaultValue; return defaultValue;
@@ -99,7 +93,8 @@ public class ElementUtils {
return (index > -1) ? name.substring(0, index) : ""; return (index > -1) ? name.substring(0, index) : "";
} }
public static ClassType getClassType(String packageName, String simpleName, List<? extends TypeParameterElement> typeParameters) { public static ClassType getClassType(String packageName, String simpleName,
List<? extends TypeParameterElement> typeParameters) {
return getClassType(ClassName.get(packageName, simpleName), typeParameters); return getClassType(ClassName.get(packageName, simpleName), typeParameters);
} }
@@ -107,7 +102,8 @@ public class ElementUtils {
return getClassType(ClassName.get(typeElement), typeParameters); return getClassType(ClassName.get(typeElement), typeParameters);
} }
public static ClassType getClassType(ClassName builderClassName, List<? extends TypeParameterElement> typeParameters) { public static ClassType getClassType(ClassName builderClassName,
List<? extends TypeParameterElement> typeParameters) {
if (typeParameters.isEmpty()) { if (typeParameters.isEmpty()) {
return new ClassType(builderClassName, builderClassName.simpleName()); return new ClassType(builderClassName, builderClassName.simpleName());
} }
@@ -115,10 +111,13 @@ public class ElementUtils {
return new ClassType(ParameterizedTypeName.get(builderClassName, typeNames), builderClassName.simpleName()); return new ClassType(ParameterizedTypeName.get(builderClassName, typeNames), builderClassName.simpleName());
} }
public static RecordClassType getRecordClassType(ProcessingEnvironment processingEnv, RecordComponentElement recordComponent, List<? extends AnnotationMirror> accessorAnnotations, List<? extends AnnotationMirror> canonicalConstructorAnnotations) { public static RecordClassType getRecordClassType(ProcessingEnvironment processingEnv,
RecordComponentElement recordComponent, List<? extends AnnotationMirror> accessorAnnotations,
List<? extends AnnotationMirror> canonicalConstructorAnnotations) {
var typeName = TypeName.get(recordComponent.asType()); var typeName = TypeName.get(recordComponent.asType());
var rawTypeName = TypeName.get(processingEnv.getTypeUtils().erasure(recordComponent.asType())); var rawTypeName = TypeName.get(processingEnv.getTypeUtils().erasure(recordComponent.asType()));
return new RecordClassType(typeName, rawTypeName, recordComponent.getSimpleName().toString(), accessorAnnotations, canonicalConstructorAnnotations); return new RecordClassType(typeName, rawTypeName, recordComponent.getSimpleName().toString(),
accessorAnnotations, canonicalConstructorAnnotations);
} }
public static String getWithMethodName(ClassType component, String prefix) { public static String getWithMethodName(ClassType component, String prefix) {
@@ -129,27 +128,30 @@ public class ElementUtils {
return prefix + Character.toUpperCase(name.charAt(0)) + name.substring(1); return prefix + Character.toUpperCase(name.charAt(0)) + name.substring(1);
} }
public static String getBuilderName(TypeElement element, RecordBuilder.Options metaData, ClassType classType, String suffix) { public static String getBuilderName(TypeElement element, RecordBuilder.Options metaData, ClassType classType,
String suffix) {
// generate the class name // generate the class name
var baseName = classType.name() + suffix; var baseName = classType.name() + suffix;
return metaData.prefixEnclosingClassNames() ? (getBuilderNamePrefix(element.getEnclosingElement()) + baseName) : baseName; return metaData.prefixEnclosingClassNames() ? (getBuilderNamePrefix(element.getEnclosingElement()) + baseName)
: baseName;
} }
public static Optional<? extends Element> findCanonicalConstructor(TypeElement record) { public static Optional<? extends Element> findCanonicalConstructor(TypeElement record) {
if ( record.getKind() != ElementKind.RECORD ) { if (record.getKind() != ElementKind.RECORD) {
return Optional.empty(); return Optional.empty();
} }
// based on https://github.com/openjdk/jdk/pull/3556/files#diff-a6270f4b50989abe733607c69038b2036306d13f77276af005d023b7fc57f1a2R2368 // based on
var componentList = record.getRecordComponents().stream().map(e -> e.asType().toString()).collect(Collectors.toList()); // https://github.com/openjdk/jdk/pull/3556/files#diff-a6270f4b50989abe733607c69038b2036306d13f77276af005d023b7fc57f1a2R2368
return record.getEnclosedElements().stream() var componentList = record.getRecordComponents().stream().map(e -> e.asType().toString())
.filter(element -> element.getKind() == ElementKind.CONSTRUCTOR) .collect(Collectors.toList());
.filter(element -> { return record.getEnclosedElements().stream().filter(element -> element.getKind() == ElementKind.CONSTRUCTOR)
var parameters = ((ExecutableElement)element).getParameters(); .filter(element -> {
var parametersList = parameters.stream().map(e -> e.asType().toString()).collect(Collectors.toList()); var parameters = ((ExecutableElement) element).getParameters();
return componentList.equals(parametersList); var parametersList = parameters.stream().map(e -> e.asType().toString())
}) .collect(Collectors.toList());
.findFirst(); return componentList.equals(parametersList);
}).findFirst();
} }
private static String getBuilderNamePrefix(Element element) { private static String getBuilderNamePrefix(Element element) {

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -28,7 +28,8 @@ class IncludeHelper {
private final List<TypeElement> classTypeElements; private final List<TypeElement> classTypeElements;
private final Map<? extends ExecutableElement, ? extends AnnotationValue> annotationValues; private final Map<? extends ExecutableElement, ? extends AnnotationValue> annotationValues;
IncludeHelper(ProcessingEnvironment processingEnv, Element element, AnnotationMirror annotationMirror, boolean packagesSupported) { IncludeHelper(ProcessingEnvironment processingEnv, Element element, AnnotationMirror annotationMirror,
boolean packagesSupported) {
annotationValues = processingEnv.getElementUtils().getElementValuesWithDefaults(annotationMirror); annotationValues = processingEnv.getElementUtils().getElementValuesWithDefaults(annotationMirror);
var value = ElementUtils.getAnnotationValue(annotationValues, "value"); var value = ElementUtils.getAnnotationValue(annotationValues, "value");
var classes = ElementUtils.getAnnotationValue(annotationValues, "classes"); var classes = ElementUtils.getAnnotationValue(annotationValues, "classes");
@@ -41,9 +42,11 @@ class IncludeHelper {
var packagesList = packages.map(ElementUtils::getAttributeStringList).orElseGet(List::of); var packagesList = packages.map(ElementUtils::getAttributeStringList).orElseGet(List::of);
if (valueList.isEmpty() && classesList.isEmpty() && packagesList.isEmpty()) { if (valueList.isEmpty() && classesList.isEmpty() && packagesList.isEmpty()) {
if (packagesSupported) { if (packagesSupported) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "At least one of \"value\", \"classes\" or \"packages\" required", element); processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
"At least one of \"value\", \"classes\" or \"packages\" required", element);
} else { } else {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "At least one of \"value\" or \"classes\" required", element); processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
"At least one of \"value\" or \"classes\" required", element);
} }
isValid = false; isValid = false;
} }
@@ -51,7 +54,8 @@ class IncludeHelper {
isValid = processList(processingEnv, isValid, element, classesList, classTypeElements); isValid = processList(processingEnv, isValid, element, classesList, classTypeElements);
packages.ifPresent(annotationValue -> processPackages(processingEnv, classTypeElements, packagesList)); packages.ifPresent(annotationValue -> processPackages(processingEnv, classTypeElements, packagesList));
} else { } else {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Could not read attribute for annotation", element); processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Could not read attribute for annotation",
element);
isValid = false; isValid = false;
} }
this.isValid = isValid; this.isValid = isValid;
@@ -70,11 +74,13 @@ class IncludeHelper {
return classTypeElements; return classTypeElements;
} }
private boolean processList(ProcessingEnvironment processingEnv, boolean isValid, Element element, List<TypeMirror> list, ArrayList<TypeElement> classTypeElements) { private boolean processList(ProcessingEnvironment processingEnv, boolean isValid, Element element,
List<TypeMirror> list, ArrayList<TypeElement> classTypeElements) {
for (var typeMirror : list) { for (var typeMirror : list) {
TypeElement typeElement = (TypeElement) processingEnv.getTypeUtils().asElement(typeMirror); TypeElement typeElement = (TypeElement) processingEnv.getTypeUtils().asElement(typeMirror);
if (typeElement == null) { if (typeElement == null) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Could not get element for: " + typeMirror, element); processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
"Could not get element for: " + typeMirror, element);
isValid = false; isValid = false;
} else { } else {
classTypeElements.add(typeElement); classTypeElements.add(typeElement);
@@ -83,7 +89,8 @@ class IncludeHelper {
return isValid; return isValid;
} }
private void processPackages(ProcessingEnvironment processingEnv, List<TypeElement> classTypeElements, List<String> packagesList) { private void processPackages(ProcessingEnvironment processingEnv, List<TypeElement> classTypeElements,
List<String> packagesList) {
for (var packageName : packagesList) { for (var packageName : packagesList) {
var packageElement = processingEnv.getElementUtils().getPackageElement(packageName); var packageElement = processingEnv.getElementUtils().getPackageElement(packageName);
for (var child : packageElement.getEnclosedElements()) { for (var child : packageElement.getEnclosedElements()) {

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -51,30 +51,33 @@ class InternalRecordInterfaceProcessor {
private record Component(ExecutableElement element, Optional<String> alternateName) { private record Component(ExecutableElement element, Optional<String> alternateName) {
} }
InternalRecordInterfaceProcessor(ProcessingEnvironment processingEnv, TypeElement iface, boolean addRecordBuilder, RecordBuilder.Options metaData, Optional<String> packageNameOpt, boolean fromTemplate) { InternalRecordInterfaceProcessor(ProcessingEnvironment processingEnv, TypeElement iface, boolean addRecordBuilder,
RecordBuilder.Options metaData, Optional<String> packageNameOpt, boolean fromTemplate) {
this.processingEnv = processingEnv; this.processingEnv = processingEnv;
packageName = packageNameOpt.orElseGet(() -> ElementUtils.getPackageName(iface)); packageName = packageNameOpt.orElseGet(() -> ElementUtils.getPackageName(iface));
recordComponents = getRecordComponents(iface); recordComponents = getRecordComponents(iface);
this.iface = iface; this.iface = iface;
ClassType ifaceClassType = ElementUtils.getClassType(iface, iface.getTypeParameters()); ClassType ifaceClassType = ElementUtils.getClassType(iface, iface.getTypeParameters());
recordClassType = ElementUtils.getClassType(packageName, getBuilderName(iface, metaData, ifaceClassType, metaData.interfaceSuffix()), iface.getTypeParameters()); recordClassType = ElementUtils.getClassType(packageName,
List<TypeVariableName> typeVariables = iface.getTypeParameters().stream().map(TypeVariableName::get).collect(Collectors.toList()); getBuilderName(iface, metaData, ifaceClassType, metaData.interfaceSuffix()), iface.getTypeParameters());
List<TypeVariableName> typeVariables = iface.getTypeParameters().stream().map(TypeVariableName::get)
.collect(Collectors.toList());
MethodSpec methodSpec = generateArgumentList(); MethodSpec methodSpec = generateArgumentList();
TypeSpec.Builder builder = TypeSpec.classBuilder(recordClassType.name()) TypeSpec.Builder builder = TypeSpec.classBuilder(recordClassType.name()).addSuperinterface(iface.asType())
.addSuperinterface(iface.asType()) .addMethod(methodSpec).addModifiers(Modifier.PUBLIC).addAnnotation(generatedRecordInterfaceAnnotation)
.addMethod(methodSpec)
.addModifiers(Modifier.PUBLIC)
.addAnnotation(generatedRecordInterfaceAnnotation)
.addTypeVariables(typeVariables); .addTypeVariables(typeVariables);
if (metaData.addClassRetainedGenerated()) { if (metaData.addClassRetainedGenerated()) {
builder.addAnnotation(recordBuilderGeneratedAnnotation); builder.addAnnotation(recordBuilderGeneratedAnnotation);
} }
if (addRecordBuilder) { if (addRecordBuilder) {
ClassType builderClassType = ElementUtils.getClassType(packageName, getBuilderName(iface, metaData, recordClassType, metaData.suffix()) + "." + metaData.withClassName(), iface.getTypeParameters()); ClassType builderClassType = ElementUtils.getClassType(packageName,
getBuilderName(iface, metaData, recordClassType, metaData.suffix()) + "."
+ metaData.withClassName(),
iface.getTypeParameters());
builder.addAnnotation(RecordBuilder.class); builder.addAnnotation(RecordBuilder.class);
builder.addSuperinterface(builderClassType.typeName()); builder.addSuperinterface(builderClassType.typeName());
if (fromTemplate) { if (fromTemplate) {
@@ -112,30 +115,29 @@ class InternalRecordInterfaceProcessor {
// javapoet does yet support records - so a class was created and we can reshape it // javapoet does yet support records - so a class was created and we can reshape it
// The class will look something like this: // The class will look something like this:
/* /*
// Auto generated by io.soabase.recordbuilder.core.RecordBuilder: https://github.com/Randgalt/record-builder * // Auto generated by io.soabase.recordbuilder.core.RecordBuilder: https://github.com/Randgalt/record-builder
package io.soabase.recordbuilder.test; * package io.soabase.recordbuilder.test;
*
import io.soabase.recordbuilder.core.RecordBuilder; * import io.soabase.recordbuilder.core.RecordBuilder; import javax.annotation.processing.Generated;
import javax.annotation.processing.Generated; *
* @Generated("io.soabase.recordbuilder.core.RecordInterface")
@Generated("io.soabase.recordbuilder.core.RecordInterface") *
@RecordBuilder * @RecordBuilder public class MyRecord implements MyInterface { void __FAKE__(String name, int age) { } }
public class MyRecord implements MyInterface { */
void __FAKE__(String name, int age) { Pattern pattern = Pattern.compile("(.*)(implements.*)(\\{)(.*" + FAKE_METHOD_NAME + ")(\\(.*\\))(.*)",
} Pattern.MULTILINE | Pattern.DOTALL);
}
*/
Pattern pattern = Pattern.compile("(.*)(implements.*)(\\{)(.*" + FAKE_METHOD_NAME + ")(\\(.*\\))(.*)", Pattern.MULTILINE | Pattern.DOTALL);
Matcher matcher = pattern.matcher(classSource); Matcher matcher = pattern.matcher(classSource);
if (!matcher.find() || matcher.groupCount() != 6) { if (!matcher.find() || matcher.groupCount() != 6) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Internal error generating record. Group count: " + matcher.groupCount(), iface); processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
"Internal error generating record. Group count: " + matcher.groupCount(), iface);
} }
String declaration = matcher.group(1).trim().replace("class", "record"); String declaration = matcher.group(1).trim().replace("class", "record");
String implementsSection = matcher.group(2).trim(); String implementsSection = matcher.group(2).trim();
String argumentList = matcher.group(5).trim(); String argumentList = matcher.group(5).trim();
StringBuilder fixedRecord = new StringBuilder(declaration).append(argumentList).append(' ').append(implementsSection).append(" {"); StringBuilder fixedRecord = new StringBuilder(declaration).append(argumentList).append(' ')
.append(implementsSection).append(" {");
alternateMethods.forEach(method -> fixedRecord.append('\n').append(method)); alternateMethods.forEach(method -> fixedRecord.append('\n').append(method));
fixedRecord.append('}'); fixedRecord.append('}');
return fixedRecord.toString(); return fixedRecord.toString();
@@ -145,27 +147,23 @@ class InternalRecordInterfaceProcessor {
MethodSpec.Builder builder = MethodSpec.methodBuilder(FAKE_METHOD_NAME); MethodSpec.Builder builder = MethodSpec.methodBuilder(FAKE_METHOD_NAME);
recordComponents.forEach(component -> { recordComponents.forEach(component -> {
String name = component.alternateName.orElseGet(() -> component.element.getSimpleName().toString()); String name = component.alternateName.orElseGet(() -> component.element.getSimpleName().toString());
ParameterSpec parameterSpec = ParameterSpec.builder(ClassName.get(component.element.getReturnType()), name).build(); ParameterSpec parameterSpec = ParameterSpec.builder(ClassName.get(component.element.getReturnType()), name)
builder.addTypeVariables(component.element.getTypeParameters().stream().map(TypeVariableName::get).collect(Collectors.toList())); .build();
builder.addTypeVariables(component.element.getTypeParameters().stream().map(TypeVariableName::get)
.collect(Collectors.toList()));
builder.addParameter(parameterSpec); builder.addParameter(parameterSpec);
}); });
return builder.build(); return builder.build();
} }
private List<String> buildAlternateMethods(List<Component> recordComponents) { private List<String> buildAlternateMethods(List<Component> recordComponents) {
return recordComponents.stream() return recordComponents.stream().filter(component -> component.alternateName.isPresent()).map(component -> {
.filter(component -> component.alternateName.isPresent()) var method = MethodSpec.methodBuilder(component.element.getSimpleName().toString())
.map(component -> { .addAnnotation(Override.class).addAnnotation(generatedRecordInterfaceAnnotation)
var method = MethodSpec.methodBuilder(component.element.getSimpleName().toString()) .returns(ClassName.get(component.element.getReturnType())).addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class) .addCode("return $L();", component.alternateName.get()).build();
.addAnnotation(generatedRecordInterfaceAnnotation) return method.toString();
.returns(ClassName.get(component.element.getReturnType())) }).collect(Collectors.toList());
.addModifiers(Modifier.PUBLIC)
.addCode("return $L();", component.alternateName.get())
.build();
return method.toString();
})
.collect(Collectors.toList());
} }
private List<Component> getRecordComponents(TypeElement iface) { private List<Component> getRecordComponents(TypeElement iface) {
@@ -173,7 +171,8 @@ class InternalRecordInterfaceProcessor {
try { try {
getRecordComponents(iface, components, new HashSet<>(), new HashSet<>()); getRecordComponents(iface, components, new HashSet<>(), new HashSet<>());
if (components.isEmpty()) { if (components.isEmpty()) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Annotated interface has no component methods", iface); processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
"Annotated interface has no component methods", iface);
} }
} catch (IllegalInterface e) { } catch (IllegalInterface e) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage(), iface); processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage(), iface);
@@ -189,29 +188,32 @@ class InternalRecordInterfaceProcessor {
} }
private void getRecordComponents(TypeElement iface, Collection<Component> components, Set<String> visitedSet, Set<String> usedNames) { private void getRecordComponents(TypeElement iface, Collection<Component> components, Set<String> visitedSet,
Set<String> usedNames) {
if (!visitedSet.add(iface.getQualifiedName().toString())) { if (!visitedSet.add(iface.getQualifiedName().toString())) {
return; return;
} }
iface.getEnclosedElements().stream() iface.getEnclosedElements().stream()
.filter(element -> (element.getKind() == ElementKind.METHOD) && !(element.getModifiers().contains(Modifier.STATIC))) .filter(element -> (element.getKind() == ElementKind.METHOD)
.map(element -> ((ExecutableElement) element)) && !(element.getModifiers().contains(Modifier.STATIC)))
.filter(element -> { .map(element -> ((ExecutableElement) element)).filter(element -> {
if (element.isDefault()) { if (element.isDefault()) {
return element.getAnnotation(IgnoreDefaultMethod.class) == null; return element.getAnnotation(IgnoreDefaultMethod.class) == null;
} }
return true; return true;
}) }).peek(element -> {
.peek(element -> {
if (!element.getParameters().isEmpty() || element.getReturnType().getKind() == TypeKind.VOID) { if (!element.getParameters().isEmpty() || element.getReturnType().getKind() == TypeKind.VOID) {
throw new IllegalInterface(String.format("Non-static, non-default methods must take no arguments and must return a value. Bad method: %s.%s()", iface.getSimpleName(), element.getSimpleName())); throw new IllegalInterface(String.format(
"Non-static, non-default methods must take no arguments and must return a value. Bad method: %s.%s()",
iface.getSimpleName(), element.getSimpleName()));
} }
if (!element.getTypeParameters().isEmpty()) { if (!element.getTypeParameters().isEmpty()) {
throw new IllegalInterface(String.format("Interface methods cannot have type parameters. Bad method: %s.%s()", iface.getSimpleName(), element.getSimpleName())); throw new IllegalInterface(
String.format("Interface methods cannot have type parameters. Bad method: %s.%s()",
iface.getSimpleName(), element.getSimpleName()));
} }
}) }).filter(element -> usedNames.add(element.getSimpleName().toString()))
.filter(element -> usedNames.add(element.getSimpleName().toString()))
.map(element -> new Component(element, stripBeanPrefix(element.getSimpleName().toString()))) .map(element -> new Component(element, stripBeanPrefix(element.getSimpleName().toString())))
.collect(Collectors.toCollection(() -> components)); .collect(Collectors.toCollection(() -> components));
iface.getInterfaces().forEach(parentIface -> { iface.getInterfaces().forEach(parentIface -> {
@@ -221,10 +223,8 @@ class InternalRecordInterfaceProcessor {
} }
private Optional<String> stripBeanPrefix(String name) { private Optional<String> stripBeanPrefix(String name) {
return javaBeanPrefixes.stream() return javaBeanPrefixes.stream().filter(prefix -> name.startsWith(prefix) && (name.length() > prefix.length()))
.filter(prefix -> name.startsWith(prefix) && (name.length() > prefix.length())) .findFirst().map(prefix -> {
.findFirst()
.map(prefix -> {
var stripped = name.substring(prefix.length()); var stripped = name.substring(prefix.length());
return Character.toLowerCase(stripped.charAt(0)) + stripped.substring(1); return Character.toLowerCase(stripped.charAt(0)) + stripped.substring(1);
}); });

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -43,8 +43,7 @@ public record OptionalType(TypeName typeName, TypeName valueType) {
if (!(component.typeName() instanceof ParameterizedTypeName parameterizedType)) { if (!(component.typeName() instanceof ParameterizedTypeName parameterizedType)) {
return Optional.of(new OptionalType(optionalType, TypeName.get(Object.class))); return Optional.of(new OptionalType(optionalType, TypeName.get(Object.class)));
} }
final TypeName containingType = parameterizedType.typeArguments.isEmpty() final TypeName containingType = parameterizedType.typeArguments.isEmpty() ? TypeName.get(Object.class)
? TypeName.get(Object.class)
: parameterizedType.typeArguments.get(0); : parameterizedType.typeArguments.get(0);
return Optional.of(new OptionalType(optionalType, containingType)); return Optional.of(new OptionalType(optionalType, containingType));
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -25,35 +25,36 @@ class RecordBuilderOptions {
private static final Map<String, Object> defaultValues = buildDefaultValues(); private static final Map<String, Object> defaultValues = buildDefaultValues();
static RecordBuilder.Options build(Map<String, String> options) { static RecordBuilder.Options build(Map<String, String> options) {
return (RecordBuilder.Options)Proxy.newProxyInstance(RecordBuilderOptions.class.getClassLoader(), new Class[]{RecordBuilder.Options.class}, (proxy, method, args) -> { return (RecordBuilder.Options) Proxy.newProxyInstance(RecordBuilderOptions.class.getClassLoader(),
var name = method.getName(); new Class[] { RecordBuilder.Options.class }, (proxy, method, args) -> {
var defaultValue = defaultValues.get(name); var name = method.getName();
var option = options.get(name); var defaultValue = defaultValues.get(name);
if (option != null) { var option = options.get(name);
if (defaultValue instanceof String) { if (option != null) {
return option; if (defaultValue instanceof String) {
} return option;
if (defaultValue instanceof Boolean) { }
return Boolean.parseBoolean(option); if (defaultValue instanceof Boolean) {
} return Boolean.parseBoolean(option);
if (defaultValue instanceof Integer) { }
return Integer.parseInt(option); if (defaultValue instanceof Integer) {
} return Integer.parseInt(option);
if (defaultValue instanceof Long) { }
return Long.parseLong(option); if (defaultValue instanceof Long) {
} return Long.parseLong(option);
if (defaultValue instanceof Double) { }
return Double.parseDouble(option); if (defaultValue instanceof Double) {
} return Double.parseDouble(option);
throw new IllegalArgumentException("Unhandled option type: " + defaultValue.getClass()); }
} throw new IllegalArgumentException("Unhandled option type: " + defaultValue.getClass());
return defaultValue; }
}); return defaultValue;
});
} }
private static Map<String, Object> buildDefaultValues() { private static Map<String, Object> buildDefaultValues() {
var workMap = new HashMap<String, Object>(); var workMap = new HashMap<String, Object>();
for ( Method method : RecordBuilder.Options.class.getDeclaredMethods()) { for (Method method : RecordBuilder.Options.class.getDeclaredMethods()) {
workMap.put(method.getName(), method.getDefaultValue()); workMap.put(method.getName(), method.getDefaultValue());
} }
workMap.put("toString", "Generated RecordBuilder.Options"); workMap.put("toString", "Generated RecordBuilder.Options");

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -38,20 +38,23 @@ import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
public class RecordBuilderProcessor public class RecordBuilderProcessor extends AbstractProcessor {
extends AbstractProcessor {
private static final String RECORD_BUILDER = RecordBuilder.class.getName(); private static final String RECORD_BUILDER = RecordBuilder.class.getName();
private static final String RECORD_BUILDER_INCLUDE = RecordBuilder.Include.class.getName().replace('$', '.'); private static final String RECORD_BUILDER_INCLUDE = RecordBuilder.Include.class.getName().replace('$', '.');
private static final String RECORD_INTERFACE = RecordInterface.class.getName(); private static final String RECORD_INTERFACE = RecordInterface.class.getName();
private static final String RECORD_INTERFACE_INCLUDE = RecordInterface.Include.class.getName().replace('$', '.'); private static final String RECORD_INTERFACE_INCLUDE = RecordInterface.Include.class.getName().replace('$', '.');
static final AnnotationSpec generatedRecordBuilderAnnotation = AnnotationSpec.builder(Generated.class).addMember("value", "$S", RecordBuilder.class.getName()).build(); static final AnnotationSpec generatedRecordBuilderAnnotation = AnnotationSpec.builder(Generated.class)
static final AnnotationSpec generatedRecordInterfaceAnnotation = AnnotationSpec.builder(Generated.class).addMember("value", "$S", RecordInterface.class.getName()).build(); .addMember("value", "$S", RecordBuilder.class.getName()).build();
static final AnnotationSpec recordBuilderGeneratedAnnotation = AnnotationSpec.builder(RecordBuilderGenerated.class).build(); static final AnnotationSpec generatedRecordInterfaceAnnotation = AnnotationSpec.builder(Generated.class)
.addMember("value", "$S", RecordInterface.class.getName()).build();
static final AnnotationSpec recordBuilderGeneratedAnnotation = AnnotationSpec.builder(RecordBuilderGenerated.class)
.build();
@Override @Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
annotations.forEach(annotation -> roundEnv.getElementsAnnotatedWith(annotation).forEach(element -> process(annotation, element))); annotations.forEach(annotation -> roundEnv.getElementsAnnotatedWith(annotation)
.forEach(element -> process(annotation, element)));
return false; return false;
} }
@@ -62,7 +65,7 @@ public class RecordBuilderProcessor
@Override @Override
public SourceVersion getSupportedSourceVersion() { public SourceVersion getSupportedSourceVersion() {
// we don't directly return RELEASE_14 as that may // we don't directly return RELEASE_14 as that may
// not exist in prior releases // not exist in prior releases
// if we're running on an older release, returning latest() // if we're running on an older release, returning latest()
// is fine as we won't encounter any records anyway // is fine as we won't encounter any records anyway
@@ -76,14 +79,16 @@ public class RecordBuilderProcessor
processRecordBuilder(typeElement, getMetaData(typeElement), Optional.empty()); processRecordBuilder(typeElement, getMetaData(typeElement), Optional.empty());
} else if (annotationClass.equals(RECORD_INTERFACE)) { } else if (annotationClass.equals(RECORD_INTERFACE)) {
var typeElement = (TypeElement) element; var typeElement = (TypeElement) element;
processRecordInterface(typeElement, element.getAnnotation(RecordInterface.class).addRecordBuilder(), getMetaData(typeElement), Optional.empty(), false); processRecordInterface(typeElement, element.getAnnotation(RecordInterface.class).addRecordBuilder(),
getMetaData(typeElement), Optional.empty(), false);
} else if (annotationClass.equals(RECORD_BUILDER_INCLUDE) || annotationClass.equals(RECORD_INTERFACE_INCLUDE)) { } else if (annotationClass.equals(RECORD_BUILDER_INCLUDE) || annotationClass.equals(RECORD_INTERFACE_INCLUDE)) {
processIncludes(element, getMetaData(element), annotationClass); processIncludes(element, getMetaData(element), annotationClass);
} else { } else {
var recordBuilderTemplate = annotation.getAnnotation(RecordBuilder.Template.class); var recordBuilderTemplate = annotation.getAnnotation(RecordBuilder.Template.class);
if (recordBuilderTemplate != null) { if (recordBuilderTemplate != null) {
if (recordBuilderTemplate.asRecordInterface()) { if (recordBuilderTemplate.asRecordInterface()) {
processRecordInterface((TypeElement) element, true, recordBuilderTemplate.options(), Optional.empty(), true); processRecordInterface((TypeElement) element, true, recordBuilderTemplate.options(),
Optional.empty(), true);
} else { } else {
processRecordBuilder((TypeElement) element, recordBuilderTemplate.options(), Optional.empty()); processRecordBuilder((TypeElement) element, recordBuilderTemplate.options(), Optional.empty());
} }
@@ -93,27 +98,34 @@ public class RecordBuilderProcessor
private RecordBuilder.Options getMetaData(Element element) { private RecordBuilder.Options getMetaData(Element element) {
var recordSpecificMetaData = element.getAnnotation(RecordBuilder.Options.class); var recordSpecificMetaData = element.getAnnotation(RecordBuilder.Options.class);
return (recordSpecificMetaData != null) ? recordSpecificMetaData : RecordBuilderOptions.build(processingEnv.getOptions()); return (recordSpecificMetaData != null) ? recordSpecificMetaData
: RecordBuilderOptions.build(processingEnv.getOptions());
} }
private void processIncludes(Element element, RecordBuilder.Options metaData, String annotationClass) { private void processIncludes(Element element, RecordBuilder.Options metaData, String annotationClass) {
var isRecordBuilderInclude = annotationClass.equals(RECORD_BUILDER_INCLUDE); var isRecordBuilderInclude = annotationClass.equals(RECORD_BUILDER_INCLUDE);
var annotationMirrorOpt = ElementUtils.findAnnotationMirror(processingEnv, element, annotationClass); var annotationMirrorOpt = ElementUtils.findAnnotationMirror(processingEnv, element, annotationClass);
if (annotationMirrorOpt.isEmpty()) { if (annotationMirrorOpt.isEmpty()) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Could not get annotation mirror for: " + annotationClass, element); processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
"Could not get annotation mirror for: " + annotationClass, element);
} else { } else {
var includeHelper = new IncludeHelper(processingEnv, element, annotationMirrorOpt.get(), isRecordBuilderInclude); var includeHelper = new IncludeHelper(processingEnv, element, annotationMirrorOpt.get(),
isRecordBuilderInclude);
if (includeHelper.isValid()) { if (includeHelper.isValid()) {
var packagePattern = ElementUtils.getStringAttribute(ElementUtils.getAnnotationValue(includeHelper.getAnnotationValues(), "packagePattern").orElse(null), "*"); var packagePattern = ElementUtils.getStringAttribute(ElementUtils
.getAnnotationValue(includeHelper.getAnnotationValues(), "packagePattern").orElse(null), "*");
for (var typeElement : includeHelper.getClassTypeElements()) { for (var typeElement : includeHelper.getClassTypeElements()) {
var packageName = buildPackageName(packagePattern, element, typeElement); var packageName = buildPackageName(packagePattern, element, typeElement);
if (packageName != null) { if (packageName != null) {
if (isRecordBuilderInclude) { if (isRecordBuilderInclude) {
processRecordBuilder(typeElement, metaData, Optional.of(packageName)); processRecordBuilder(typeElement, metaData, Optional.of(packageName));
} else { } else {
var addRecordBuilderOpt = ElementUtils.getAnnotationValue(includeHelper.getAnnotationValues(), "addRecordBuilder"); var addRecordBuilderOpt = ElementUtils
var addRecordBuilder = addRecordBuilderOpt.map(ElementUtils::getBooleanAttribute).orElse(true); .getAnnotationValue(includeHelper.getAnnotationValues(), "addRecordBuilder");
processRecordInterface(typeElement, addRecordBuilder, metaData, Optional.of(packageName), false); var addRecordBuilder = addRecordBuilderOpt.map(ElementUtils::getBooleanAttribute)
.orElse(true);
processRecordInterface(typeElement, addRecordBuilder, metaData, Optional.of(packageName),
false);
} }
} }
} }
@@ -130,7 +142,8 @@ public class RecordBuilderProcessor
if (builderElement instanceof PackageElement) { if (builderElement instanceof PackageElement) {
return replaced.replace("@", ((PackageElement) builderElement).getQualifiedName().toString()); return replaced.replace("@", ((PackageElement) builderElement).getQualifiedName().toString());
} }
return replaced.replace("@", ((PackageElement) builderElement.getEnclosingElement()).getQualifiedName().toString()); return replaced.replace("@",
((PackageElement) builderElement.getEnclosingElement()).getQualifiedName().toString());
} }
private PackageElement findPackageElement(Element actualElement, Element includedClass) { private PackageElement findPackageElement(Element actualElement, Element includedClass) {
@@ -144,37 +157,63 @@ public class RecordBuilderProcessor
return findPackageElement(actualElement, includedClass.getEnclosingElement()); return findPackageElement(actualElement, includedClass.getEnclosingElement());
} }
private void processRecordInterface(TypeElement element, boolean addRecordBuilder, RecordBuilder.Options metaData, Optional<String> packageName, boolean fromTemplate) { private void processRecordInterface(TypeElement element, boolean addRecordBuilder, RecordBuilder.Options metaData,
Optional<String> packageName, boolean fromTemplate) {
if (!element.getKind().isInterface()) { if (!element.getKind().isInterface()) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "RecordInterface only valid for interfaces.", element); processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
"RecordInterface only valid for interfaces.", element);
return; return;
} }
var internalProcessor = new InternalRecordInterfaceProcessor(processingEnv, element, addRecordBuilder, metaData, packageName, fromTemplate);
validateMetaData(metaData, element);
var internalProcessor = new InternalRecordInterfaceProcessor(processingEnv, element, addRecordBuilder, metaData,
packageName, fromTemplate);
if (!internalProcessor.isValid()) { if (!internalProcessor.isValid()) {
return; return;
} }
writeRecordInterfaceJavaFile(element, internalProcessor.packageName(), internalProcessor.recordClassType(), internalProcessor.recordType(), metaData, internalProcessor::toRecord); writeRecordInterfaceJavaFile(element, internalProcessor.packageName(), internalProcessor.recordClassType(),
internalProcessor.recordType(), metaData, internalProcessor::toRecord);
} }
private void processRecordBuilder(TypeElement record, RecordBuilder.Options metaData, Optional<String> packageName) { private void processRecordBuilder(TypeElement record, RecordBuilder.Options metaData,
Optional<String> packageName) {
// we use string based name comparison for the element kind, // we use string based name comparison for the element kind,
// as the ElementKind.RECORD enum doesn't exist on JRE releases // as the ElementKind.RECORD enum doesn't exist on JRE releases
// older than Java 14, and we don't want to throw unexpected // older than Java 14, and we don't want to throw unexpected
// NoSuchFieldErrors // NoSuchFieldErrors
if (!"RECORD".equals(record.getKind().name())) { if (!"RECORD".equals(record.getKind().name())) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "RecordBuilder only valid for records.", record); processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "RecordBuilder only valid for records.",
record);
return; return;
} }
validateMetaData(metaData, record);
var internalProcessor = new InternalRecordBuilderProcessor(processingEnv, record, metaData, packageName); var internalProcessor = new InternalRecordBuilderProcessor(processingEnv, record, metaData, packageName);
writeRecordBuilderJavaFile(record, internalProcessor.packageName(), internalProcessor.builderClassType(), internalProcessor.builderType(), metaData); writeRecordBuilderJavaFile(record, internalProcessor.packageName(), internalProcessor.builderClassType(),
internalProcessor.builderType(), metaData);
} }
private void writeRecordBuilderJavaFile(TypeElement record, String packageName, ClassType builderClassType, TypeSpec builderType, RecordBuilder.Options metaData) { private void validateMetaData(RecordBuilder.Options metaData, Element record) {
var useImmutableCollections = metaData.useImmutableCollections();
var useUnmodifiableCollections = metaData.useUnmodifiableCollections();
if (useImmutableCollections && useUnmodifiableCollections) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.MANDATORY_WARNING,
"Options.useUnmodifiableCollections property is ignored as Options.useImmutableCollections is set to true",
record);
}
}
private void writeRecordBuilderJavaFile(TypeElement record, String packageName, ClassType builderClassType,
TypeSpec builderType, RecordBuilder.Options metaData) {
// produces the Java file // produces the Java file
JavaFile javaFile = javaFileBuilder(packageName, builderType, metaData); JavaFile javaFile = javaFileBuilder(packageName, builderType, metaData);
Filer filer = processingEnv.getFiler(); Filer filer = processingEnv.getFiler();
try { try {
String fullyQualifiedName = packageName.isEmpty() ? builderClassType.name() : (packageName + "." + builderClassType.name()); String fullyQualifiedName = packageName.isEmpty() ? builderClassType.name()
: (packageName + "." + builderClassType.name());
JavaFileObject sourceFile = filer.createSourceFile(fullyQualifiedName); JavaFileObject sourceFile = filer.createSourceFile(fullyQualifiedName);
try (Writer writer = sourceFile.openWriter()) { try (Writer writer = sourceFile.openWriter()) {
javaFile.writeTo(writer); javaFile.writeTo(writer);
@@ -184,7 +223,8 @@ public class RecordBuilderProcessor
} }
} }
private void writeRecordInterfaceJavaFile(TypeElement element, String packageName, ClassType classType, TypeSpec type, RecordBuilder.Options metaData, Function<String, String> toRecordProc) { private void writeRecordInterfaceJavaFile(TypeElement element, String packageName, ClassType classType,
TypeSpec type, RecordBuilder.Options metaData, Function<String, String> toRecordProc) {
JavaFile javaFile = javaFileBuilder(packageName, type, metaData); JavaFile javaFile = javaFileBuilder(packageName, type, metaData);
String classSourceCode = javaFile.toString(); String classSourceCode = javaFile.toString();
@@ -193,7 +233,8 @@ public class RecordBuilderProcessor
Filer filer = processingEnv.getFiler(); Filer filer = processingEnv.getFiler();
try { try {
String fullyQualifiedName = packageName.isEmpty() ? classType.name() : (packageName + "." + classType.name()); String fullyQualifiedName = packageName.isEmpty() ? classType.name()
: (packageName + "." + classType.name());
JavaFileObject sourceFile = filer.createSourceFile(fullyQualifiedName); JavaFileObject sourceFile = filer.createSourceFile(fullyQualifiedName);
try (Writer writer = sourceFile.openWriter()) { try (Writer writer = sourceFile.openWriter()) {
writer.write(recordSourceCode); writer.write(recordSourceCode);
@@ -204,7 +245,8 @@ public class RecordBuilderProcessor
} }
private JavaFile javaFileBuilder(String packageName, TypeSpec type, RecordBuilder.Options metaData) { private JavaFile javaFileBuilder(String packageName, TypeSpec type, RecordBuilder.Options metaData) {
var javaFileBuilder = JavaFile.builder(packageName, type).skipJavaLangImports(true).indent(metaData.fileIndent()); var javaFileBuilder = JavaFile.builder(packageName, type).skipJavaLangImports(true)
.indent(metaData.fileIndent());
var comment = metaData.fileComment(); var comment = metaData.fileComment();
if ((comment != null) && !comment.isEmpty()) { if ((comment != null) && !comment.isEmpty()) {
javaFileBuilder.addFileComment(comment); javaFileBuilder.addFileComment(comment);

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -25,7 +25,9 @@ public class RecordClassType extends ClassType {
private final List<? extends AnnotationMirror> accessorAnnotations; private final List<? extends AnnotationMirror> accessorAnnotations;
private final List<? extends AnnotationMirror> canonicalConstructorAnnotations; private final List<? extends AnnotationMirror> canonicalConstructorAnnotations;
public RecordClassType(TypeName typeName, TypeName rawTypeName, String name, List<? extends AnnotationMirror> accessorAnnotations, List<? extends AnnotationMirror> canonicalConstructorAnnotations) { public RecordClassType(TypeName typeName, TypeName rawTypeName, String name,
List<? extends AnnotationMirror> accessorAnnotations,
List<? extends AnnotationMirror> canonicalConstructorAnnotations) {
super(typeName, name); super(typeName, name);
this.rawTypeName = rawTypeName; this.rawTypeName = rawTypeName;
this.accessorAnnotations = accessorAnnotations; this.accessorAnnotations = accessorAnnotations;

View File

@@ -1,9 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2019 The original author or authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<groupId>io.soabase.record-builder</groupId> <groupId>io.soabase.record-builder</groupId>
<artifactId>record-builder</artifactId> <artifactId>record-builder</artifactId>
<version>34-SNAPSHOT</version> <version>38-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -47,6 +64,12 @@
<artifactId>junit-jupiter</artifactId> <artifactId>junit-jupiter</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -18,11 +18,7 @@ package io.soabase.recordbuilder.test;
import io.soabase.recordbuilder.core.RecordBuilder; import io.soabase.recordbuilder.core.RecordBuilder;
import io.soabase.recordbuilder.core.RecordInterface; import io.soabase.recordbuilder.core.RecordInterface;
@RecordInterface.Include({ @RecordInterface.Include({ Thingy.class })
Thingy.class @RecordBuilder.Include({ Nested.NestedRecord.class })
})
@RecordBuilder.Include({
Nested.NestedRecord.class
})
public class Builder { public class Builder {
} }

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2019 The original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.soabase.recordbuilder.test;
import io.soabase.recordbuilder.core.RecordBuilder;
import java.time.Instant;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
@RecordBuilder
@RecordBuilder.Options(addSingleItemCollectionBuilders = true, useImmutableCollections = true, mutableListClassName = "PersonalizedMutableList")
public record CollectionCopying<T>(List<String> list, Set<T> set, Map<Instant, T> map, Collection<T> collection,
int count) implements CollectionCopyingBuilder.With<T> {
}

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -25,10 +25,11 @@ import java.util.Set;
@RecordBuilder @RecordBuilder
@RecordBuilder.Options(useImmutableCollections = true, addFunctionalMethodsToWith = true) @RecordBuilder.Options(useImmutableCollections = true, addFunctionalMethodsToWith = true)
public record CollectionRecord<T, X extends Point>(List<T> l, Set<T> s, Map<T, X> m, public record CollectionRecord<T, X extends Point>(List<T> l, Set<T> s, Map<T, X> m, Collection<X> c)
Collection<X> c) implements CollectionRecordBuilder.With<T, X> { implements CollectionRecordBuilder.With<T, X> {
public static void main(String[] args) { public static void main(String[] args) {
var r = new CollectionRecord<>(List.of("hey"), Set.of("there"), Map.of("one", new Point(10, 20)), Set.of(new Point(30, 40))); var r = new CollectionRecord<>(List.of("hey"), Set.of("there"), Map.of("one", new Point(10, 20)),
Set.of(new Point(30, 40)));
Instant now = r.map((l1, s1, m1, c1) -> Instant.now()); Instant now = r.map((l1, s1, m1, c1) -> Instant.now());
r.accept((l1, s1, m1, c1) -> { r.accept((l1, s1, m1, c1) -> {
}); });

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -24,5 +24,6 @@ import java.util.Set;
@RecordBuilder @RecordBuilder
@RecordBuilder.Options(useImmutableCollections = true) @RecordBuilder.Options(useImmutableCollections = true)
public record CollectionRecordConflicts(List<String> __list, Set<String> __set, Map<String, String> __map, Collection<String> __collection) implements CollectionRecordConflictsBuilder.With { public record CollectionRecordConflicts(List<String> __list, Set<String> __set, Map<String, String> __map,
Collection<String> __collection) implements CollectionRecordConflictsBuilder.With {
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,14 +16,13 @@
package io.soabase.recordbuilder.test; package io.soabase.recordbuilder.test;
import java.util.List; import java.util.List;
import java.util.Map;
import io.soabase.recordbuilder.core.RecordBuilder; import io.soabase.recordbuilder.core.RecordBuilder;
import io.soabase.recordbuilder.test.CustomMethodNamesBuilder.Bean; import io.soabase.recordbuilder.test.CustomMethodNamesBuilder.Bean;
@RecordBuilder @RecordBuilder
@RecordBuilder.Options( @RecordBuilder.Options(setterPrefix = "set", getterPrefix = "get", booleanPrefix = "is", beanClassName = "Bean")
setterPrefix = "set", getterPrefix = "get", booleanPrefix = "is", beanClassName = "Bean") public record CustomMethodNames<K, V>(Map<K, V> kvMap, int theValue, List<Integer> theList, boolean theBoolean)
public record CustomMethodNames( implements Bean, CustomMethodNamesBuilder.With {
int theValue,
List<Integer> theList,
boolean theBoolean) implements Bean {
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -21,10 +21,8 @@ import javax.lang.model.type.ErrorType;
import java.util.List; import java.util.List;
@RecordBuilder @RecordBuilder
public record ExceptionDetails( public record ExceptionDetails(String internalMessage, String endUserMessage, String httpStatus, ErrorType errorType,
String internalMessage, String endUserMessage, String httpStatus, List<String> jsonProblems, Throwable cause) {
ErrorType errorType, List<String> jsonProblems, Throwable cause
) {
@Override @Override
public List<String> jsonProblems() { public List<String> jsonProblems() {
if (jsonProblems == null) { if (jsonProblems == null) {

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -22,5 +22,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
@RecordBuilderFull @RecordBuilderFull
public record FullRecord(@NotNull List<Number> numbers, @NotNull Map<Number, FullRecord> fullRecords, @NotNull String justAString) { public record FullRecord(@NotNull List<Number> numbers, @NotNull Map<Number, FullRecord> fullRecords,
@NotNull String justAString) {
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,5 +20,6 @@ import io.soabase.recordbuilder.core.RecordBuilder;
@RecordBuilder.Options(prefixEnclosingClassNames = false) @RecordBuilder.Options(prefixEnclosingClassNames = false)
@RecordBuilder.Include(IncludeWithOption.Hey.class) @RecordBuilder.Include(IncludeWithOption.Hey.class)
public class IncludeWithOption { public class IncludeWithOption {
public static record Hey(String s){} public static record Hey(String s) {
}
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,10 +17,6 @@ package io.soabase.recordbuilder.test;
import io.soabase.recordbuilder.core.RecordBuilder; import io.soabase.recordbuilder.core.RecordBuilder;
@RecordBuilder.Template(options = @RecordBuilder.Options( @RecordBuilder.Template(options = @RecordBuilder.Options(fileComment = "This is a test", withClassName = "Com"), asRecordInterface = true)
fileComment = "This is a test",
withClassName = "Com"),
asRecordInterface = true
)
public @interface MyInterfaceTemplate { public @interface MyInterfaceTemplate {
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,10 +17,6 @@ package io.soabase.recordbuilder.test;
import io.soabase.recordbuilder.core.RecordBuilder; import io.soabase.recordbuilder.core.RecordBuilder;
@RecordBuilder.Template(options = @RecordBuilder.Options( @RecordBuilder.Template(options = @RecordBuilder.Options(fileComment = "This is a test", withClassName = "Com"))
fileComment = "This is a test", public @interface MyTemplate {
withClassName = "Com"
))
public @interface MyTemplate
{
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,5 +16,6 @@
package io.soabase.recordbuilder.test; package io.soabase.recordbuilder.test;
public class Nested { public class Nested {
record NestedRecord(int x, int y){} record NestedRecord(int x, int y) {
}
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,9 +1,5 @@
package io.soabase.recordbuilder.test; /*
* Copyright 2019 The original author or authors
import io.soabase.recordbuilder.core.RecordBuilder;
/**
* Copyright 2019 Jordan Zimmerman
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,6 +13,22 @@ import io.soabase.recordbuilder.core.RecordBuilder;
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package io.soabase.recordbuilder.test;
import io.soabase.recordbuilder.core.RecordBuilder;
/**
* Copyright 2019 Jordan Zimmerman
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
@RecordBuilder.Options(addStaticBuilder = false) @RecordBuilder.Options(addStaticBuilder = false)
@RecordBuilder @RecordBuilder
public record NoStaticBuilder(String foo) { public record NoStaticBuilder(String foo) {

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -15,4 +15,5 @@
*/ */
package io.soabase.recordbuilder.test; package io.soabase.recordbuilder.test;
public record Pair<T, U>(T t, U u) {} public record Pair<T, U>(T t, U u) {
}

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -15,4 +15,5 @@
*/ */
package io.soabase.recordbuilder.test; package io.soabase.recordbuilder.test;
public record Point(int x, int y) {} public record Point(int x, int y) {
}

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -18,4 +18,5 @@ package io.soabase.recordbuilder.test;
import io.soabase.recordbuilder.core.RecordBuilder; import io.soabase.recordbuilder.core.RecordBuilder;
@RecordBuilder @RecordBuilder
public record RecordWithAnR(int r, String b) {} public record RecordWithAnR(int r, String b) {
}

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -26,4 +26,6 @@ import java.util.OptionalLong;
@RecordBuilder.Options(emptyDefaultForOptional = true, addConcreteSettersForOptional = true) @RecordBuilder.Options(emptyDefaultForOptional = true, addConcreteSettersForOptional = true)
@RecordBuilder @RecordBuilder
public record RecordWithOptional(@NotNull Optional<String> value, Optional raw, OptionalInt i, OptionalLong l, OptionalDouble d) {} public record RecordWithOptional(@NotNull Optional<String> value, Optional raw, OptionalInt i, OptionalLong l,
OptionalDouble d) {
}

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -23,4 +23,6 @@ import io.soabase.recordbuilder.core.RecordBuilder;
@RecordBuilder.Options(emptyDefaultForOptional = true) @RecordBuilder.Options(emptyDefaultForOptional = true)
@RecordBuilder @RecordBuilder
public record RecordWithOptional2(Optional<String> value, Optional raw, OptionalInt i, OptionalLong l, OptionalDouble d) {} public record RecordWithOptional2(Optional<String> value, Optional raw, OptionalInt i, OptionalLong l,
OptionalDouble d) {
}

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -24,5 +24,6 @@ import javax.validation.constraints.NotNull;
@RecordBuilder @RecordBuilder
@RecordBuilder.Options(useValidationApi = true) @RecordBuilder.Options(useValidationApi = true)
public record RequestWithValid(@NotNull @Valid Part part) implements RequestWithValidBuilder.With { public record RequestWithValid(@NotNull @Valid Part part) implements RequestWithValidBuilder.With {
public record Part(@NotBlank String name) {} public record Part(@NotBlank String name) {
}
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -22,5 +22,6 @@ import java.util.List;
@RecordBuilder.Options(interpretNotNulls = true) @RecordBuilder.Options(interpretNotNulls = true)
@RecordBuilder @RecordBuilder
public record RequiredRecord(@NotNull String hey, @NotNull int i, @NotNull List<String> l) implements RequiredRecordBuilder.With { public record RequiredRecord(@NotNull String hey, @NotNull int i, @NotNull List<String> l)
implements RequiredRecordBuilder.With {
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -24,11 +24,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
@RecordBuilder @RecordBuilder
@RecordBuilder.Options( @RecordBuilder.Options(addSingleItemCollectionBuilders = true, singleItemBuilderPrefix = "add1", useImmutableCollections = true, addFunctionalMethodsToWith = true)
addSingleItemCollectionBuilders = true, public record SingleItems<T>(List<String> strings, Set<List<T>> sets, Map<Instant, T> map, Collection<T> collection)
singleItemBuilderPrefix = "add1", implements SingleItemsBuilder.With<T> {
useImmutableCollections = true,
addFunctionalMethodsToWith = true
)
public record SingleItems<T>(List<String> strings, Set<List<T>> sets, Map<Instant, T> map, Collection<T> collection) implements SingleItemsBuilder.With<T> {
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -18,8 +18,6 @@ package io.soabase.recordbuilder.test;
import io.soabase.recordbuilder.core.RecordBuilder; import io.soabase.recordbuilder.core.RecordBuilder;
@RecordBuilder @RecordBuilder
@RecordBuilder.Options( @RecordBuilder.Options(enableGetters = false, enableWither = false)
enableGetters = false, public record StrippedFeaturesRecord(int aField) {
enableWither = false }
)
public record StrippedFeaturesRecord(int aField) {}

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -18,6 +18,5 @@ package io.soabase.recordbuilder.test;
import java.time.Instant; import java.time.Instant;
@MyTemplate @MyTemplate
public record TemplateTest(String text, Instant date) implements TemplateTestBuilder.Com public record TemplateTest(String text, Instant date) implements TemplateTestBuilder.Com {
{
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2019 The original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.soabase.recordbuilder.test;
import io.soabase.recordbuilder.core.RecordBuilder;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
@RecordBuilder
@RecordBuilder.Options(useUnmodifiableCollections = true)
record UnmodifiableCollectionsRecord(List<Integer> aList, Set<String> orderedSet, Map<String, Integer> orderedMap,
Collection<String> aCollection) {
}

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -24,9 +24,8 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
@RecordBuilder @RecordBuilder
@RecordBuilder.Options( @RecordBuilder.Options(addSingleItemCollectionBuilders = true, useImmutableCollections = true)
addSingleItemCollectionBuilders = true, public record WildcardSingleItems<T>(List<? extends String> strings, Set<? extends List<? extends T>> sets,
useImmutableCollections = true Map<? extends Instant, ? extends T> map, Collection<? extends T> collection)
) implements WildcardSingleItemsBuilder.With<T> {
public record WildcardSingleItems<T>(List<? extends String> strings, Set<? extends List<? extends T>> sets, Map<? extends Instant, ? extends T> map, Collection<? extends T> collection) implements WildcardSingleItemsBuilder.With<T> {
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,9 +17,6 @@ package io.soabase.recordbuilder.test.includes;
import io.soabase.recordbuilder.core.RecordBuilder; import io.soabase.recordbuilder.core.RecordBuilder;
@RecordBuilder.Include( @RecordBuilder.Include(packages = "io.soabase.recordbuilder.test.includes.pack", classes = JustATest.class)
packages = "io.soabase.recordbuilder.test.includes.pack",
classes = JustATest.class
)
public class IncludeFactory { public class IncludeFactory {
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -24,5 +24,6 @@ import java.util.Map;
@RecordBuilderFull @RecordBuilderFull
@RecordBuilderGenerated @RecordBuilderGenerated
public record FullRecordForJacoco(@NotNull List<Number> numbers, @NotNull Map<Number, FullRecordForJacoco> fullRecords, @NotNull String justAString) { public record FullRecordForJacoco(@NotNull List<Number> numbers, @NotNull Map<Number, FullRecordForJacoco> fullRecords,
@NotNull String justAString) {
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,8 +13,8 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
@RecordBuilder.Include(value = { Point.class, Pair.class }, packagePattern = "*.foo")
@RecordBuilder.Include(value = {Point.class, Pair.class}, packagePattern = "*.foo") @RecordBuilder.Options(fileComment = "MyLicense - Auto generated")
@RecordInterface.Include(value = Customer.class, addRecordBuilder = false, packagePattern = "*.bar") @RecordInterface.Include(value = Customer.class, addRecordBuilder = false, packagePattern = "*.bar")
package io.soabase.recordbuilder.test; package io.soabase.recordbuilder.test;

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -0,0 +1,25 @@
/*
* Copyright 2019 The original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.soabase.recordbuilder.test.visibility;
import io.soabase.recordbuilder.core.RecordBuilder;
import javax.lang.model.element.Modifier;
@RecordBuilder.Options(builderClassModifiers = { Modifier.PUBLIC })
@RecordBuilder
record PackagePrivateRecordWithPublicBuilder(String value) {
}

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -27,7 +27,7 @@ class TestCollections {
@Test @Test
void testRecordBuilderOptionsCopied() { void testRecordBuilderOptionsCopied() {
try { try {
assertNotNull(CollectionInterfaceRecordBuilder.class.getDeclaredMethod("__list", List.class)); assertNotNull(CollectionInterfaceRecordBuilder.class.getDeclaredMethod("__list", Collection.class));
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
Assertions.fail(e); Assertions.fail(e);
} }
@@ -52,30 +52,20 @@ class TestCollections {
map.put("one", Point(10, 20)); map.put("one", Point(10, 20));
var collectionAsSet = new HashSet<Point>(); var collectionAsSet = new HashSet<Point>();
collectionAsSet.add(Point(30, 40)); collectionAsSet.add(Point(30, 40));
var r = CollectionRecordBuilder.<String, Point>builder() var r = CollectionRecordBuilder.<String, Point> builder().l(list).s(set).m(map).c(collectionAsSet).build();
.l(list)
.s(set)
.m(map)
.c(collectionAsSet)
.build();
assertValues(r, list, set, map, collectionAsSet); assertValues(r, list, set, map, collectionAsSet);
assertValueChanges(r, list, set, map, collectionAsSet); assertValueChanges(r, list, set, map, collectionAsSet);
assertImmutable(r); assertImmutable(r);
var collectionAsList = new ArrayList<Point>(); var collectionAsList = new ArrayList<Point>();
var x = CollectionRecordBuilder.<String, Point>builder() var x = CollectionRecordBuilder.<String, Point> builder().l(list).s(set).m(map).c(collectionAsList).build();
.l(list)
.s(set)
.m(map)
.c(collectionAsList)
.build();
assertTrue(x.c() instanceof List); assertTrue(x.c() instanceof List);
} }
@Test @Test
void testCollectionRecordImmutableWithers() { void testCollectionRecordImmutableWithers() {
var r = CollectionRecordBuilder.<String, Point>builder().build(); var r = CollectionRecordBuilder.<String, Point> builder().build();
var list = new ArrayList<String>(); var list = new ArrayList<String>();
list.add("one"); list.add("one");
@@ -113,7 +103,8 @@ class TestCollections {
assertThrows(UnsupportedOperationException.class, () -> r.c().add(Point(1, 2))); assertThrows(UnsupportedOperationException.class, () -> r.c().add(Point(1, 2)));
} }
private void assertValueChanges(CollectionRecord<String, Point> r, ArrayList<String> list, HashSet<String> set, HashMap<String, Point> map, HashSet<Point> collectionAsSet) { private void assertValueChanges(CollectionRecord<String, Point> r, ArrayList<String> list, HashSet<String> set,
HashMap<String, Point> map, HashSet<Point> collectionAsSet) {
list.add("two"); list.add("two");
set.add("two"); set.add("two");
map.put("two", Point(50, 60)); map.put("two", Point(50, 60));
@@ -125,7 +116,8 @@ class TestCollections {
assertNotEquals(r.c(), collectionAsSet); assertNotEquals(r.c(), collectionAsSet);
} }
private void assertValues(CollectionRecord<String, Point> r, ArrayList<String> list, HashSet<String> set, HashMap<String, Point> map, HashSet<Point> collectionAsSet) { private void assertValues(CollectionRecord<String, Point> r, ArrayList<String> list, HashSet<String> set,
HashMap<String, Point> map, HashSet<Point> collectionAsSet) {
assertEquals(r.l(), list); assertEquals(r.l(), list);
assertEquals(r.s(), set); assertEquals(r.s(), set);
assertEquals(r.m(), map); assertEquals(r.m(), map);

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2019 The original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.soabase.recordbuilder.test;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class TestCollectionsBuilder {
@Test
void testCollectionsBuilderReturnNonNullEmptyCollections() {
CollectionRecordBuilder<Object, Point> builder = CollectionRecordBuilder.builder();
Assertions.assertNotNull(builder.l());
Assertions.assertTrue(builder.l().isEmpty());
Assertions.assertNotNull(builder.c());
Assertions.assertTrue(builder.c().isEmpty());
Assertions.assertNotNull(builder.m());
Assertions.assertTrue(builder.m().isEmpty());
Assertions.assertNotNull(builder.s());
Assertions.assertTrue(builder.s().isEmpty());
}
}

View File

@@ -0,0 +1,116 @@
/*
* Copyright 2019 The original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.soabase.recordbuilder.test;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.time.Instant;
import java.util.*;
public class TestImmutableCollections {
@Test
public void testImmutableListNotCopiedWhenNotChanged() {
var item = CollectionCopyingBuilder.<String> builder().addList("a").addList("b").addList("c").build();
Assertions.assertEquals(item.list(), List.of("a", "b", "c"));
var oldList = item.list();
var copy = item.with().count(1).build();
Assertions.assertSame(oldList, copy.list());
var otherCopy = item.with().count(2).build();
Assertions.assertSame(oldList, otherCopy.list());
}
@Test
public void testImmutableSetNotCopiedWhenNotChanged() {
var item = CollectionCopyingBuilder.<String> builder().addSet(Arrays.asList("1", "2", "3")).build();
Assertions.assertEquals(item.set(), Set.of("1", "2", "3"));
var oldSet = item.set();
var copy = item.with().count(1).build();
Assertions.assertSame(oldSet, copy.set());
var otherCopy = item.with().count(2).build();
Assertions.assertSame(oldSet, otherCopy.set());
}
@Test
public void testImmutableCollectionNotCopiedWhenNotChanged() {
var item = CollectionCopyingBuilder.<String> builder().collection(List.of("foo", "bar", "baz")).build();
Assertions.assertEquals(item.collection(), List.of("foo", "bar", "baz"));
var oldCollection = item.collection();
var copy = item.with().count(1).build();
Assertions.assertSame(oldCollection, copy.collection());
var otherCopy = item.with().count(2).build();
Assertions.assertSame(oldCollection, otherCopy.collection());
}
@Test
public void testImmutableMapNotCopiedWhenNotChanged() {
var item = CollectionCopyingBuilder.<String> builder().addMap(Instant.MAX, "future")
.addMap(Instant.MIN, "before").build();
Assertions.assertEquals(item.map(), Map.of(Instant.MAX, "future", Instant.MIN, "before"));
var oldMap = item.map();
var copy = item.with().count(1).build();
Assertions.assertSame(oldMap, copy.map());
var otherCopy = item.with().count(2).build();
Assertions.assertSame(oldMap, otherCopy.map());
}
@Test
void testSourceListNotModified() {
var item = new CollectionCopying<>(new ArrayList<>(), null, null, null, 0);
var modifiedItem = CollectionCopyingBuilder.builder(item).addList("a").build();
Assertions.assertEquals(modifiedItem.list(), List.of("a"));
Assertions.assertTrue(item.list().isEmpty());
}
@Test
void testSourceSetNotModified() {
var item = new CollectionCopying<>(null, new HashSet<>(), null, null, 0);
var modifiedItem = CollectionCopyingBuilder.builder(item).addSet("a").build();
Assertions.assertEquals(modifiedItem.set(), Set.of("a"));
Assertions.assertTrue(item.set().isEmpty());
}
@Test
void testSourceMapNotModified() {
var item = new CollectionCopying<>(null, null, new HashMap<>(), null, 0);
var modifiedItem = CollectionCopyingBuilder.builder(item).addMap(Instant.MIN, "a").build();
Assertions.assertEquals(modifiedItem.map(), Map.of(Instant.MIN, "a"));
Assertions.assertTrue(item.map().isEmpty());
}
}

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -36,12 +36,7 @@ class TestOptional {
@Test @Test
void testRawSetters() { void testRawSetters() {
var record = RecordWithOptionalBuilder.builder() var record = RecordWithOptionalBuilder.builder().value("value").raw("rawValue").i(42).l(424242L).d(42.42)
.value("value")
.raw("rawValue")
.i(42)
.l(424242L)
.d(42.42)
.build(); .build();
Assertions.assertEquals(Optional.of("value"), record.value()); Assertions.assertEquals(Optional.of("value"), record.value());
Assertions.assertEquals(Optional.of("rawValue"), record.raw()); Assertions.assertEquals(Optional.of("rawValue"), record.raw());
@@ -52,13 +47,8 @@ class TestOptional {
@Test @Test
void testOptionalSetters() { void testOptionalSetters() {
var record = RecordWithOptional2Builder.builder() var record = RecordWithOptional2Builder.builder().value(Optional.of("value")).raw(Optional.of("rawValue"))
.value(Optional.of("value")) .i(OptionalInt.of(42)).l(OptionalLong.of(424242L)).d(OptionalDouble.of(42.42)).build();
.raw(Optional.of("rawValue"))
.i(OptionalInt.of(42))
.l(OptionalLong.of(424242L))
.d(OptionalDouble.of(42.42))
.build();
Assertions.assertEquals(Optional.of("value"), record.value()); Assertions.assertEquals(Optional.of("value"), record.value());
Assertions.assertEquals(Optional.of("rawValue"), record.raw()); Assertions.assertEquals(Optional.of("rawValue"), record.raw());
Assertions.assertEquals(OptionalInt.of(42), record.i()); Assertions.assertEquals(OptionalInt.of(42), record.i());
@@ -72,9 +62,7 @@ class TestOptional {
String value = null; String value = null;
// when // when
var record = RecordWithOptionalBuilder.builder() var record = RecordWithOptionalBuilder.builder().value(value).build();
.value(value)
.build();
// then // then
Assertions.assertEquals(Optional.empty(), record.value()); Assertions.assertEquals(Optional.empty(), record.value());

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2019 The original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.soabase.recordbuilder.test;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class TestOptionsOnPackage {
@Test
void testOptionsOnInclude() throws IOException {
String text = Files.readString(
Path.of("target/generated-sources/annotations/io/soabase/recordbuilder/test/foo/PairBuilder.java"));
Assertions.assertTrue(text.contains("// MyLicense - Auto generated"));
}
}

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -33,10 +33,7 @@ class TestRecordBuilderFull {
@Test @Test
void testImmutable() { void testImmutable() {
var record = FullRecordBuilder.builder() var record = FullRecordBuilder.builder().fullRecords(new HashMap<>()).numbers(new ArrayList<>()).justAString("")
.fullRecords(new HashMap<>())
.numbers(new ArrayList<>())
.justAString("")
.build(); .build();
Assertions.assertThrows(UnsupportedOperationException.class, () -> record.fullRecords().put(1, record)); Assertions.assertThrows(UnsupportedOperationException.class, () -> record.fullRecords().put(1, record));
Assertions.assertThrows(UnsupportedOperationException.class, () -> record.numbers().add(1)); Assertions.assertThrows(UnsupportedOperationException.class, () -> record.numbers().add(1));

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -26,11 +26,9 @@ import java.time.Instant;
import static io.soabase.recordbuilder.test.SimpleGenericRecordBuilder.SimpleGenericRecord; import static io.soabase.recordbuilder.test.SimpleGenericRecordBuilder.SimpleGenericRecord;
import static io.soabase.recordbuilder.test.SimpleRecordBuilder.SimpleRecord; import static io.soabase.recordbuilder.test.SimpleRecordBuilder.SimpleRecord;
public class TestRecordInterface public class TestRecordInterface {
{
@Test @Test
public void testHasDefaults() public void testHasDefaults() {
{
var r1 = new HasDefaultsRecord(Instant.MIN, Instant.MAX); var r1 = new HasDefaultsRecord(Instant.MIN, Instant.MAX);
var r2 = r1.with(b -> b.tomorrow(Instant.MIN)); var r2 = r1.with(b -> b.tomorrow(Instant.MIN));
Assertions.assertEquals(Instant.MIN, r1.time()); Assertions.assertEquals(Instant.MIN, r1.time());
@@ -40,9 +38,8 @@ public class TestRecordInterface
} }
@Test @Test
public void testStaticConstructor() public void testStaticConstructor() {
{ var simple = SimpleRecord(10, "hey");
var simple = SimpleRecord(10,"hey");
Assertions.assertEquals(simple.i(), 10); Assertions.assertEquals(simple.i(), 10);
Assertions.assertEquals(simple.s(), "hey"); Assertions.assertEquals(simple.s(), "hey");
@@ -53,26 +50,15 @@ public class TestRecordInterface
} }
@Test @Test
public void testBuilderStreamWithValues() public void testBuilderStreamWithValues() {
{ var stream = SimpleRecordBuilder.stream(SimpleRecordBuilder.builder().i(19).s("value").build()).toList();
var stream = SimpleRecordBuilder.stream(SimpleRecordBuilder.builder() Assertions.assertEquals(stream, List.of(Map.entry("i", 19), Map.entry("s", "value")));
.i(19)
.s("value")
.build())
.toList();
Assertions.assertEquals(stream, List.of(
Map.entry("i", 19),
Map.entry("s", "value")));
} }
@Test @Test
public void testBuilderStreamWithNulls() public void testBuilderStreamWithNulls() {
{ var stream = SimpleRecordBuilder.stream(SimpleRecordBuilder.builder().build()).toList();
var stream = SimpleRecordBuilder.stream(SimpleRecordBuilder.builder() Assertions.assertEquals(stream,
.build()) List.of(new SimpleImmutableEntry<>("i", 0), new SimpleImmutableEntry<>("s", null)));
.toList();
Assertions.assertEquals(stream, List.of(
new SimpleImmutableEntry<>("i", 0),
new SimpleImmutableEntry<>("s", null)));
} }
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -26,26 +26,16 @@ import java.util.Set;
public class TestSingleItems { public class TestSingleItems {
@Test @Test
public void testInternalCollections() public void testInternalCollections() {
{
var now = Instant.now(); var now = Instant.now();
var item = SingleItemsBuilder.<String>builder() var item = SingleItemsBuilder.<String> builder().add1Map(now, "now").add1Map(Instant.MIN, "before")
.add1Map(now, "now") .add1Sets(Arrays.asList("1", "2")).add1Sets(List.of("3")).add1Strings("a").add1Strings("b")
.add1Map(Instant.MIN, "before") .add1Strings("c").build();
.add1Sets(Arrays.asList("1", "2"))
.add1Sets(List.of("3"))
.add1Strings("a")
.add1Strings("b")
.add1Strings("c")
.build();
Assertions.assertEquals(item.map(), Map.of(now, "now", Instant.MIN, "before")); Assertions.assertEquals(item.map(), Map.of(now, "now", Instant.MIN, "before"));
Assertions.assertEquals(item.sets(), Set.of(List.of("1", "2"), List.of("3"))); Assertions.assertEquals(item.sets(), Set.of(List.of("1", "2"), List.of("3")));
Assertions.assertEquals(item.strings(), List.of("a", "b", "c")); Assertions.assertEquals(item.strings(), List.of("a", "b", "c"));
var copy = item.with() var copy = item.with().add1Strings("new").add1Map(Instant.MAX, "after").add1Sets(List.of("10", "20", "30"))
.add1Strings("new")
.add1Map(Instant.MAX, "after")
.add1Sets(List.of("10", "20", "30"))
.build(); .build();
Assertions.assertNotEquals(item, copy); Assertions.assertNotEquals(item, copy);
Assertions.assertEquals(copy.map(), Map.of(now, "now", Instant.MIN, "before", Instant.MAX, "after")); Assertions.assertEquals(copy.map(), Map.of(now, "now", Instant.MIN, "before", Instant.MAX, "after"));
@@ -55,20 +45,15 @@ public class TestSingleItems {
var stringsToAdd = Arrays.asList("x", "y", "z"); var stringsToAdd = Arrays.asList("x", "y", "z");
var listToAdd = Arrays.asList(List.of("aa", "bb"), List.of("cc")); var listToAdd = Arrays.asList(List.of("aa", "bb"), List.of("cc"));
var mapToAdd = Map.of(now.plusMillis(1), "now+1", now.plusMillis(2), "now+2"); var mapToAdd = Map.of(now.plusMillis(1), "now+1", now.plusMillis(2), "now+2");
var streamed = SingleItemsBuilder.builder(item) var streamed = SingleItemsBuilder.builder(item).add1Strings(stringsToAdd.stream()).add1Sets(listToAdd.stream())
.add1Strings(stringsToAdd.stream()) .add1Map(mapToAdd.entrySet().stream()).build();
.add1Sets(listToAdd.stream()) Assertions.assertEquals(streamed.map(),
.add1Map(mapToAdd.entrySet().stream()) Map.of(now, "now", Instant.MIN, "before", now.plusMillis(1), "now+1", now.plusMillis(2), "now+2"));
.build(); Assertions.assertEquals(streamed.sets(),
Assertions.assertEquals(streamed.map(), Map.of(now, "now", Instant.MIN, "before", now.plusMillis(1), "now+1", now.plusMillis(2), "now+2")); Set.of(List.of("1", "2"), List.of("3"), List.of("aa", "bb"), List.of("cc")));
Assertions.assertEquals(streamed.sets(), Set.of(List.of("1", "2"), List.of("3"), List.of("aa", "bb"), List.of("cc")));
Assertions.assertEquals(streamed.strings(), Arrays.asList("a", "b", "c", "x", "y", "z")); Assertions.assertEquals(streamed.strings(), Arrays.asList("a", "b", "c", "x", "y", "z"));
var nulls = SingleItemsBuilder.builder(item) var nulls = SingleItemsBuilder.builder(item).strings(null).sets(null).map(null).build();
.strings(null)
.sets(null)
.map(null)
.build();
Assertions.assertEquals(nulls.map(), Map.of()); Assertions.assertEquals(nulls.map(), Map.of());
Assertions.assertEquals(nulls.sets(), Set.of()); Assertions.assertEquals(nulls.sets(), Set.of());
Assertions.assertEquals(nulls.strings(), List.of()); Assertions.assertEquals(nulls.strings(), List.of());

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2019 The original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.soabase.recordbuilder.test;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import static java.util.Map.entry;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class TestUnmodifiableCollectionsBuilder {
@Test
void shouldWrapCollectionsWithUnmodifiableView() {
// given
var list = new ArrayList<Integer>();
list.add(2);
list.add(1);
list.add(0);
var orderedSet = new LinkedHashSet<String>();
orderedSet.add("C");
orderedSet.add("B");
orderedSet.add("A");
var orderedMap = new LinkedHashMap<String, Integer>();
orderedMap.put("C", 2);
orderedMap.put("B", 1);
orderedMap.put("A", 0);
var collection = new HashSet<String>();
collection.add("C");
collection.add("B");
collection.add("A");
// when
var record = UnmodifiableCollectionsRecordBuilder.builder().aList(list).orderedSet(orderedSet)
.orderedMap(orderedMap).aCollection(collection).build();
// then
assertAll(() -> assertThrows(UnsupportedOperationException.class, () -> record.aList().add(9)),
() -> assertThat(record.aList()).containsExactly(2, 1, 0),
() -> assertThrows(UnsupportedOperationException.class, () -> record.orderedSet().add("newElement")),
() -> assertThat(record.orderedSet()).containsExactly("C", "B", "A"),
() -> assertThrows(UnsupportedOperationException.class, () -> record.orderedMap().put("newElement", 9)),
() -> assertThat(record.orderedMap()).containsExactly(entry("C", 2), entry("B", 1), entry("A", 0)),
() -> assertThrows(UnsupportedOperationException.class, () -> record.aCollection().add("newElement")),
() -> assertThat(record.aCollection()).containsExactlyInAnyOrder("C", "B", "A"));
}
}

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -46,11 +46,9 @@ class TestValidation {
@Test @Test
void testRequestWithValid() { void testRequestWithValid() {
Assertions.assertDoesNotThrow(() -> RequestWithValidBuilder.builder() Assertions.assertDoesNotThrow(
.part(new RequestWithValid.Part("jsfjsf")) () -> RequestWithValidBuilder.builder().part(new RequestWithValid.Part("jsfjsf")).build());
.build()); Assertions.assertThrows(ValidationException.class,
Assertions.assertThrows(ValidationException.class, () -> RequestWithValidBuilder.builder() () -> RequestWithValidBuilder.builder().part(new RequestWithValid.Part("")).build());
.part(new RequestWithValid.Part(""))
.build());
} }
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -18,52 +18,48 @@ package io.soabase.recordbuilder.test;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Stream; import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
public class TestVariousOptions { public class TestVariousOptions {
@Test @Test
public void builderGetsCustomSetterAndGetterNames() { public void builderGetsCustomSetterAndGetterNames() {
var obj = CustomMethodNamesBuilder.builder() var obj = CustomMethodNamesBuilder.builder().setKvMap(Map.of(1, "one")).setTheValue(1).setTheList(List.of(2))
.setTheValue(1) .setTheBoolean(true);
.setTheList(List.of(2)) assertEquals(1, obj.getTheValue());
.setTheBoolean(true); assertEquals(List.of(2), obj.getTheList());
assertEquals(1, obj.getTheValue()); assertTrue(obj.isTheBoolean());
assertEquals(List.of(2), obj.getTheList()); assertEquals(new CustomMethodNames<>(Map.of(1, "one"), 1, List.of(2), true), obj.build());
assertTrue(obj.isTheBoolean()); }
assertEquals(new CustomMethodNames(1, List.of(2), true), obj.build());
}
@Test @Test
public void withBuilderGetsCustomSetterAndGetterNames() { public void withBuilderGetsCustomSetterAndGetterNames() {
var obj = CustomMethodNamesBuilder.from(CustomMethodNamesBuilder.builder() var obj = CustomMethodNamesBuilder.from(
.setTheValue(1) CustomMethodNamesBuilder.builder().setTheValue(1).setTheList(List.of(2)).setTheBoolean(true).build());
.setTheList(List.of(2)) assertEquals(1, obj.theValue());
.setTheBoolean(true) assertEquals(List.of(2), obj.theList());
.build()); assertTrue(obj.theBoolean());
assertEquals(1, obj.getTheValue()); }
assertEquals(List.of(2), obj.getTheList());
assertTrue(obj.isTheBoolean());
}
@Test @Test
public void recordHasPrefixedGetters() { public void recordHasPrefixedGetters() {
var obj = new CustomMethodNames(1, List.of(2), true); var obj = new CustomMethodNames<>(Map.of(1, "one"), 1, List.of(2), true);
assertEquals(1, obj.getTheValue()); assertEquals(1, obj.getTheValue());
assertEquals(List.of(2), obj.getTheList()); assertEquals(List.of(2), obj.getTheList());
assertTrue(obj.isTheBoolean()); assertTrue(obj.isTheBoolean());
} }
@Test @Test
public void noStaticBuilder() { public void noStaticBuilder() {
boolean hasStaticBuilder = Stream.of(NoStaticBuilderBuilder.class.getDeclaredMethods()) boolean hasStaticBuilder = Stream.of(NoStaticBuilderBuilder.class.getDeclaredMethods())
.anyMatch(method -> method.getName().equals("NoStaticBuilder")); .anyMatch(method -> method.getName().equals("NoStaticBuilder"));
assertFalse(hasStaticBuilder); assertFalse(hasStaticBuilder);
hasStaticBuilder = Stream.of(SimpleRecordBuilder.class.getDeclaredMethods()) hasStaticBuilder = Stream.of(SimpleRecordBuilder.class.getDeclaredMethods())
.anyMatch(method -> method.getName().equals("SimpleRecord")); .anyMatch(method -> method.getName().equals("SimpleRecord"));
assertTrue(hasStaticBuilder); assertTrue(hasStaticBuilder);
} }
} }

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -29,4 +29,14 @@ class TestVisibility {
Assertions.assertTrue(Modifier.isPublic(WrapperProtectedRecordBuilder.class.getModifiers())); Assertions.assertTrue(Modifier.isPublic(WrapperProtectedRecordBuilder.class.getModifiers()));
} }
@Test
void testMatchesWithModifers() {
Assertions.assertFalse(Modifier.isPublic(PackagePrivateRecordWithPublicBuilder.class.getModifiers()));
Assertions.assertFalse(Modifier.isPrivate(PackagePrivateRecordWithPublicBuilder.class.getModifiers()));
Assertions.assertFalse(Modifier.isProtected(PackagePrivateRecordWithPublicBuilder.class.getModifiers()));
Assertions.assertTrue(Modifier.isPublic(PackagePrivateRecordWithPublicBuilderBuilder.class.getModifiers()));
}
} }

View File

@@ -1,9 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2019 The original author or authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<groupId>io.soabase.record-builder</groupId> <groupId>io.soabase.record-builder</groupId>
<artifactId>record-builder</artifactId> <artifactId>record-builder</artifactId>
<version>34-SNAPSHOT</version> <version>38-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -1,5 +1,5 @@
/** /*
* Copyright 2019 Jordan Zimmerman * Copyright 2019 The original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
Copyright 2019 Jordan Zimmerman Copyright ${year} The original author or authors
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.