Merge remote-tracking branch 'origin/master' into jacksonizedAccessors

This commit is contained in:
Jan Rieke committed 2025-03-31 13:40:12 +02:00
commit 9bb4204f51
67 files changed
+999 -359

No files matched your search

+53 -40
View File
@@ -6,7 +6,7 @@ on:
jobs:
build:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- name: Checkout
@@ -38,13 +38,13 @@ jobs:
test-javac:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
needs: build
env:
EA_JDK: 23
EA_JDK: 24
strategy:
matrix:
jdk: [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]
jdk: [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
goal: [javacCurrent]
include:
- jdk: 11
@@ -71,15 +71,6 @@ jobs:
website: jdk.java.net
release: ${{ matrix.jdk }}
version: latest
- name: Install Ant
env:
ANT_VERSION: 1.10.14
run: |
wget https://archive.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.zip
unzip apache-ant-$ANT_VERSION-bin.zip -d "${HOME}"
echo "ANT_HOME=${HOME}/apache-ant-$ANT_VERSION" >> $GITHUB_ENV
echo "${HOME}/apache-ant-$ANT_VERSION/bin" >> $GITHUB_PATH
- name: Cache dependencies
uses: actions/cache@v4
@@ -95,43 +86,36 @@ jobs:
run: ant -noinput test.${{ matrix.goal }}
test-eclipse:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
needs: build
strategy:
matrix:
version:
- eclipse-oxygen
- eclipse-202006
- eclipse-202006-jdk8
- eclipse-202212
- eclipse-202309
- eclipse-202312
- eclipse-202403
- eclipse-202406
- eclipse-202409
- eclipse-I-build
- eclipse-oxygen-full
- eclipse-2022-03-full
- eclipse-2023-09-full
- eclipse-2023-12-full
- eclipse-2024-03-full
- eclipse-2024-06-full
- eclipse-2024-09-full
- eclipse-I-build-full
- ecj11
- ecj14
- ecj16
- ecj19
- eclipse-oxygen
- eclipse-202006
- eclipse-202006-jdk8
- eclipse-202212
- eclipse-202403
- eclipse-202503
- eclipse-I-build
- eclipse-oxygen-full
- eclipse-2022-03-full
- eclipse-2024-03-full
- eclipse-2025-03-full
- eclipse-I-build-full
- ecj11
- ecj14
- ecj16
- ecj19
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: 17
java-version: 21
distribution: 'zulu'
- name: Cache dependencies
@@ -164,7 +148,7 @@ jobs:
run: xvfb-run ant -noinput dist test.${{ matrix.version }}
docker-integration-test:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
needs: build
strategy:
matrix:
@@ -192,3 +176,32 @@ jobs:
- name: Compile in container
run: docker run --entrypoint="" -v $(pwd)/lombok.jar:/workspace/lombok.jar $IMAGE_NAME /bin/bash -c "cd classpath; ${{ matrix.tool.cmd }}"
manual-tests:
runs-on: ubuntu-24.04
needs: build
strategy:
matrix:
jdk: [8, 11, 17, 21, 23]
dir: [compileTests]
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up JDK ${{ matrix.jdk }}
uses: actions/setup-java@v4
with:
java-version: ${{ matrix.jdk }}
distribution: 'zulu'
- uses: actions/download-artifact@v4
with:
name: lombok.jar
path: dist
- name: Run tests
working-directory: ./test/manual/${{ matrix.dir }}/
run: ./runTests.sh
+2 -1
View File
@@ -1,10 +1,10 @@
Lombok contributors in alphabetical order:
Adam Juraszek <juriad@gmail.com>
Aleksandar Kanchev <136312841+kanchev1@users.noreply.github.com>
Aleksandr Zhelezniak <lekan1992@gmail.com>
Amine Touzani <ttzn.dev@gmail.com>
Andre Brait <andrebrait@gmail.com>
Anshuman Mishra <a.mishra@uber.com>
Bulgakov Alexander <buls@yandex.ru>
Caleb Brinkman <floralvikings@gmail.com>
Christian Nüssgens <christian@nuessgens.com>
@@ -37,6 +37,7 @@ Mateusz Matela <mateusz.matela@gmail.com>
Michael Dardis <git@md-5.net>
Michael Ernst <mernst@alum.mit.edu>
Michiel Verheul <cheelio@gmail.com>
MoonFruit <dkmoonfruit@gmail.com>
Ole Ludwig <o.ludwig@wtnet.de>
Pascal Bihler <pascal@qfs.de>
Peter Grant <petercgrant@users.noreply.github.com>
-6
View File
@@ -1,11 +1,5 @@
# Project Lombok
<sub>Sponsored Content</sub>
> [![Sponsor logo Fern](https://projectlombok.org/files/logos/fern.png)](https://form.typeform.com/to/bShdJw7z)
> Offer API docs that look as good as Stripe's using our sponsor [Fern](https://form.typeform.com/to/bShdJw7z). Request a [preview of your docs](https://form.typeform.com/to/bShdJw7z) on Fern.
<br/>
**Project Lombok** is a java library that automatically plugs into your editor and build tools, spicing up your java.
Never write another getter or equals method again, with one annotation your class has a fully featured builder, automate your logging variables, and much more.
@@ -0,0 +1,14 @@
<ivy-module version="2.0">
<info organisation="org.projectlombok" module="lombok.patcher" revision="0.54" publication="20250306230000">
<license name="MIT License" url="https://www.opensource.org/licenses/mit-license.php" />
<ivyauthor name="rzwitserloot" url="https://github.com/rzwitserloot" />
<ivyauthor name="rspilker" url="https://github.com/rspilker" />
<description homepage="https://projectlombok.org/" />
</info>
<configurations>
<conf name="default" />
</configurations>
<publications>
<artifact conf="default" url="https://projectlombok.org/downloads/lombok.patcher-0.54.jar" />
</publications>
</ivy-module>
+15 -69
View File
@@ -30,18 +30,14 @@
<conf name="eclipse-oxygen" />
<conf name="eclipse-202006" />
<conf name="eclipse-202212" />
<conf name="eclipse-202309" />
<conf name="eclipse-202312" />
<conf name="eclipse-202403" />
<conf name="eclipse-202406" />
<conf name="eclipse-202409" />
<conf name="eclipse-202503" />
<conf name="mapstruct" />
</configurations>
<dependencies>
<dependency org="org.projectlombok" name="lombok.patcher" rev="0.52" conf="build,stripe->default" />
<dependency org="org.projectlombok" name="lombok.patcher" rev="0.54" conf="build,stripe->default" />
<dependency org="zwitserloot.com" name="cmdreader" rev="1.2" conf="build,stripe->runtime" />
<dependency org="org.apache.ant" name="ant" rev="1.10.5" conf="build->default" />
<dependency org="org.apache.ant" name="ant-junit" rev="1.10.5" conf="build->default" />
@@ -112,44 +108,6 @@
<dependency org="org.eclipse.platform" name="org.eclipse.osgi" rev="3.15.300" conf="eclipse-202006->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.text" rev="3.10.200" conf="eclipse-202006->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.runtime" rev="3.26.100" conf="eclipse-202212->default" transitive="false" />
<dependency org="org.eclipse.jdt" name="org.eclipse.jdt.core" rev="3.32.0" conf="eclipse-202212->default" transitive="false" />
<dependency org="org.eclipse.jdt" name="org.eclipse.jdt.ui" rev="3.27.100" conf="eclipse-202212->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.equinox.common" rev="3.17.0" conf="eclipse-202212->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.equinox.registry" rev="3.11.200" conf="eclipse-202212->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.equinox.app" rev="1.6.200" conf="eclipse-202212->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.resources" rev="3.18.100" conf="eclipse-202212->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.contenttype" rev="3.8.200" conf="eclipse-202212->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.jobs" rev="3.13.200" conf="eclipse-202212->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.osgi" rev="3.18.200" conf="eclipse-202212->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.text" rev="3.12.300" conf="eclipse-202212->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.runtime" rev="3.29.0" conf="eclipse-202309->default" transitive="false" />
<dependency org="org.eclipse.jdt" name="org.eclipse.jdt.core" rev="3.35.0" conf="eclipse-202309->default" transitive="false" />
<dependency org="org.eclipse.jdt" name="org.eclipse.jdt.ui" rev="3.30.0" conf="eclipse-202309->default" transitive="false" />
<dependency org="org.eclipse.jdt" name="ecj" rev="3.35.0" conf="eclipse-202309->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.equinox.common" rev="3.18.100" conf="eclipse-202309->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.equinox.registry" rev="3.11.300" conf="eclipse-202309->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.equinox.app" rev="1.6.300" conf="eclipse-202309->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.resources" rev="3.19.100" conf="eclipse-202309->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.contenttype" rev="3.9.100" conf="eclipse-202309->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.jobs" rev="3.15.0" conf="eclipse-202309->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.osgi" rev="3.18.500" conf="eclipse-202309->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.text" rev="3.13.100" conf="eclipse-202309->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.runtime" rev="3.30.0" conf="eclipse-202312->default" transitive="false" />
<dependency org="org.eclipse.jdt" name="org.eclipse.jdt.core" rev="3.36.0" conf="eclipse-202312->default" transitive="false" />
<dependency org="org.eclipse.jdt" name="org.eclipse.jdt.ui" rev="3.31.0" conf="eclipse-202312->default" transitive="false" />
<dependency org="org.eclipse.jdt" name="ecj" rev="3.36.0" conf="eclipse-202312->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.equinox.common" rev="3.18.200" conf="eclipse-202312->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.equinox.registry" rev="3.11.400" conf="eclipse-202312->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.equinox.app" rev="1.6.400" conf="eclipse-202312->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.resources" rev="3.20.0" conf="eclipse-202312->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.contenttype" rev="3.9.200" conf="eclipse-202312->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.jobs" rev="3.15.100" conf="eclipse-202312->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.osgi" rev="3.18.600" conf="eclipse-202312->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.text" rev="3.13.100" conf="eclipse-202312->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.runtime" rev="3.31.0" conf="eclipse-202403->default" transitive="false" />
<dependency org="org.eclipse.jdt" name="org.eclipse.jdt.core" rev="3.37.0" conf="eclipse-202403->default" transitive="false" />
<dependency org="org.eclipse.jdt" name="org.eclipse.jdt.ui" rev="3.32.0" conf="eclipse-202403->default" transitive="false" />
@@ -163,31 +121,19 @@
<dependency org="org.eclipse.platform" name="org.eclipse.osgi" rev="3.19.0" conf="eclipse-202403->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.text" rev="3.14.0" conf="eclipse-202403->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.runtime" rev="3.31.100" conf="eclipse-202406->default" transitive="false" />
<dependency org="org.eclipse.jdt" name="org.eclipse.jdt.core" rev="3.38.0" conf="eclipse-202406->default" transitive="false" />
<dependency org="org.eclipse.jdt" name="org.eclipse.jdt.ui" rev="3.32.100" conf="eclipse-202406->default" transitive="false" />
<dependency org="org.eclipse.jdt" name="ecj" rev="3.38.0" conf="eclipse-202406->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.equinox.common" rev="3.19.100" conf="eclipse-202406->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.equinox.registry" rev="3.12.100" conf="eclipse-202406->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.equinox.app" rev="1.7.100" conf="eclipse-202406->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.resources" rev="3.20.200" conf="eclipse-202406->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.contenttype" rev="3.9.400" conf="eclipse-202406->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.jobs" rev="3.15.300" conf="eclipse-202406->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.osgi" rev="3.20.0" conf="eclipse-202406->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.text" rev="3.14.100" conf="eclipse-202406->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.runtime" rev="3.31.100" conf="eclipse-202409->default" transitive="false" />
<dependency org="org.eclipse.jdt" name="org.eclipse.jdt.core" rev="3.39.0" conf="eclipse-202409->default" transitive="false" />
<dependency org="org.eclipse.jdt" name="org.eclipse.jdt.ui" rev="3.33.0" conf="eclipse-202409->default" transitive="false" />
<dependency org="org.eclipse.jdt" name="ecj" rev="3.39.0" conf="eclipse-202409->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.equinox.common" rev="3.19.100" conf="eclipse-202409->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.equinox.registry" rev="3.12.100" conf="eclipse-202409->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.equinox.app" rev="1.7.200" conf="eclipse-202409->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.resources" rev="3.21.0" conf="eclipse-202409->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.contenttype" rev="3.9.500" conf="eclipse-202409->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.jobs" rev="3.15.400" conf="eclipse-202409->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.osgi" rev="3.21.0" conf="eclipse-202409->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.text" rev="3.14.100" conf="eclipse-202409->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.runtime" rev="3.33.0" conf="eclipse-202503->default" transitive="false" />
<dependency org="org.eclipse.jdt" name="org.eclipse.jdt.core" rev="3.41.0" conf="eclipse-202503->default" transitive="false" />
<dependency org="org.eclipse.jdt" name="org.eclipse.jdt.ui" rev="3.34.0" conf="eclipse-202503->default" transitive="false" />
<dependency org="org.eclipse.jdt" name="ecj" rev="3.41.0" conf="eclipse-202503->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.equinox.common" rev="3.20.0" conf="eclipse-202503->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.equinox.registry" rev="3.12.300" conf="eclipse-202503->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.equinox.app" rev="1.7.300" conf="eclipse-202503->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.resources" rev="3.22.100" conf="eclipse-202503->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.contenttype" rev="3.9.600" conf="eclipse-202503->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.core.jobs" rev="3.15.500" conf="eclipse-202503->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.osgi" rev="3.23.0" conf="eclipse-202503->default" transitive="false" />
<dependency org="org.osgi" name="org.osgi.service.prefs" rev="1.1.2" conf="eclipse-202503->default" transitive="false" />
<dependency org="org.eclipse.platform" name="org.eclipse.text" rev="3.14.300" conf="eclipse-202503->default" transitive="false" />
<!-- integration with other libraries -->
<dependency org="org.mapstruct" name="mapstruct-processor" rev="1.3.1.Final" conf="mapstruct->default" transitive="false" />
+4 -16
View File
@@ -160,28 +160,16 @@ This buildfile is part of projectlombok.org. It sets up the build itself.
<fetchdep.eclipse.osgi name="oxygen" version="4.7" />
</target>
<target name="deps.eclipse.2022-03" depends="deps.rtstubs18, compile.support">
<target name="deps.eclipse.202203" depends="deps.rtstubs18, compile.support">
<fetchdep.eclipse.osgi name="2022-03" version="4.23" />
</target>
<target name="deps.eclipse.2023-09" depends="deps.rtstubs18, compile.support">
<fetchdep.eclipse.osgi name="2023-09" version="4.29" />
</target>
<target name="deps.eclipse.2023-12" depends="deps.rtstubs18, compile.support">
<fetchdep.eclipse.osgi name="2023-12" version="4.30" />
</target>
<target name="deps.eclipse.2024-03" depends="deps.rtstubs18, compile.support">
<target name="deps.eclipse.202403" depends="deps.rtstubs18, compile.support">
<fetchdep.eclipse.osgi name="2024-03" version="4.31" />
</target>
<target name="deps.eclipse.2024-06" depends="deps.rtstubs18, compile.support">
<fetchdep.eclipse.osgi name="2024-06" version="4.32" />
</target>
<target name="deps.eclipse.2024-09" depends="deps.rtstubs18, compile.support">
<fetchdep.eclipse.osgi name="2024-09" version="4.33" />
<target name="deps.eclipse.202503" depends="deps.rtstubs18, compile.support">
<fetchdep.eclipse.osgi name="2025-03" version="4.35" />
</target>
<target name="deps.eclipse.integration" depends="deps.rtstubs18, compile.support">
+12 -47
View File
@@ -1,5 +1,5 @@
<!--
Copyright (C) 2020-2023 The Project Lombok Authors.
Copyright (C) 2020-2025 The Project Lombok Authors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -154,8 +154,8 @@ This buildfile is part of projectlombok.org. It takes care of compiling and runn
<!-- For non-LTS versions, feel free to aggressively update these to the current non-LTS openjdk version, and delete them once they roll out of the 6 month window. -->
<target name="test.javac23" depends="test.compile, test.formatter.compile" description="runs the tests on your default VM, using javac23 as underlying compiler">
<test.javacX version="23" />
<target name="test.javac24" depends="test.compile, test.formatter.compile" description="runs the tests on your default VM, using javac24 as underlying compiler">
<test.javacX version="24" />
</target>
<target name="test.javacCurrent" depends="test.compile, test.formatter.compile" description="runs the tests on your default VM, using its javac as underlying compiler">
@@ -198,11 +198,6 @@ This buildfile is part of projectlombok.org. It takes care of compiling and runn
</sequential>
</macrodef>
<target name="test.eclipse-202212" depends="test.compile, test.formatter.compile" description="runs the tests on your default VM, testing the 2022-12 release of eclipse">
<fetchdep.eclipse version="202212" />
<test.eclipse-X version="202212" />
</target>
<target name="test.eclipse-oxygen" depends="test.compile, test.formatter.compile" description="runs the tests on your default VM, testing the oxygen release of eclipse">
<test.eclipse-X version="oxygen" />
</target>
@@ -217,29 +212,14 @@ This buildfile is part of projectlombok.org. It takes care of compiling and runn
<test.eclipse-X version="202006" compiler.compliance.level="8" />
</target>
<target name="test.eclipse-202309" depends="test.compile, test.formatter.compile" description="runs the tests on your default VM, testing the 2023-09 release of eclipse">
<fetchdep.eclipse version="202309" />
<test.eclipse-X version="202309" />
</target>
<target name="test.eclipse-202312" depends="test.compile, test.formatter.compile" description="runs the tests on your default VM, testing the 2023-12 release of eclipse">
<fetchdep.eclipse version="202312" />
<test.eclipse-X version="202312" />
</target>
<target name="test.eclipse-202403" depends="test.compile, test.formatter.compile" description="runs the tests on your default VM, testing the 2024-03 release of eclipse">
<fetchdep.eclipse version="202403" />
<test.eclipse-X version="202403" />
</target>
<target name="test.eclipse-202406" depends="test.compile, test.formatter.compile" description="runs the tests on your default VM, testing the 2024-06 release of eclipse">
<fetchdep.eclipse version="202406" />
<test.eclipse-X version="202406" />
</target>
<target name="test.eclipse-202409" depends="test.compile, test.formatter.compile" description="runs the tests on your default VM, testing the 2024-09 release of eclipse">
<fetchdep.eclipse version="202409" />
<test.eclipse-X version="202409" />
<target name="test.eclipse-202503" depends="test.compile, test.formatter.compile" description="runs the tests on your default VM, testing the 2025-03 release of eclipse">
<fetchdep.eclipse version="202503" />
<test.eclipse-X version="202503" />
</target>
<target name="test.eclipse-I-build" depends="test.compile, test.formatter.compile, deps.rtstubs18, compile.support" description="runs the tests on your default VM, testing the latest integration build of eclipse">
@@ -257,6 +237,7 @@ This buildfile is part of projectlombok.org. It takes care of compiling and runn
<arg value="osgi.bundle:org.eclipse.core.jobs" />
<arg value="osgi.bundle:org.eclipse.osgi" />
<arg value="osgi.bundle:org.eclipse.text" />
<arg value="osgi.bundle:org.osgi.service.prefs" />
</bundles>
</fetchdep.eclipse.updatesite>
<path id="cp.eclipse-I-build">
@@ -302,28 +283,12 @@ This buildfile is part of projectlombok.org. It takes care of compiling and runn
<test.eclipse-X-full version="oxygen" />
</target>
<target name="test.eclipse-2022-03-full" depends="test.eclipse.compile, test.formatter.compile, deps.eclipse.2022-03" description="runs the full eclipse tests on your default VM, testing the 2022-03 release of eclipse">
<test.eclipse-X-full version="2022-03" />
</target>
<target name="test.eclipse-2023-09-full" depends="test.eclipse.compile, test.formatter.compile, deps.eclipse.2023-09" description="runs the full eclipse tests on your default VM, testing the 2023-09 release of eclipse">
<test.eclipse-X-full version="2023-09" />
</target>
<target name="test.eclipse-2023-12-full" depends="test.eclipse.compile, test.formatter.compile, deps.eclipse.2023-12" description="runs the full eclipse tests on your default VM, testing the 2023-12 release of eclipse">
<test.eclipse-X-full version="2023-12" />
</target>
<target name="test.eclipse-2024-03-full" depends="test.eclipse.compile, test.formatter.compile, deps.eclipse.2024-03" description="runs the full eclipse tests on your default VM, testing the 2024-03 release of eclipse">
<target name="test.eclipse-202403-full" depends="test.eclipse.compile, test.formatter.compile, deps.eclipse.202403" description="runs the full eclipse tests on your default VM, testing the 2024-03 release of eclipse">
<test.eclipse-X-full version="2024-03" />
</target>
<target name="test.eclipse-2024-06-full" depends="test.eclipse.compile, test.formatter.compile, deps.eclipse.2024-06" description="runs the full eclipse tests on your default VM, testing the 2024-06 release of eclipse">
<test.eclipse-X-full version="2024-06" />
</target>
<target name="test.eclipse-2024-09-full" depends="test.eclipse.compile, test.formatter.compile, deps.eclipse.2024-09" description="runs the full eclipse tests on your default VM, testing the 2024-09 release of eclipse">
<test.eclipse-X-full version="2024-09" />
<target name="test.eclipse-202503-full" depends="test.eclipse.compile, test.formatter.compile, deps.eclipse.202503" description="runs the full eclipse tests on your default VM, testing the 2025-03 release of eclipse">
<test.eclipse-X-full version="2025-03" />
</target>
<target name="test.eclipse-I-build-full" depends="test.eclipse.compile, test.formatter.compile, deps.eclipse.integration" description="runs the full eclipse tests on your default VM, testing the latest integration build of eclipse">
@@ -371,6 +336,6 @@ This buildfile is part of projectlombok.org. It takes care of compiling and runn
<test.ecj-X version="19" />
</target>
<target name="test" depends="test.javacCurrent, test.eclipse-202212" description="runs the tests against the default JVM, javac, and eclipse" />
<target name="test.broad" depends="test.javac8, test.javac17, test.javac21, test.javac23, test.eclipse-oxygen, test.eclipse-202212, test.eclipse-202006-jdk8" description="runs the tests against the default JVM, javac, and eclipse" />
<target name="test" depends="test.javacCurrent, test.eclipse-202503" description="runs the tests against the default JVM, javac, and eclipse" />
<target name="test.broad" depends="test.javac8, test.javac17, test.javac21, test.javac24, test.eclipse-oxygen, test.eclipse-202503, test.eclipse-202006-jdk8" description="runs the tests against the default JVM, javac, and eclipse" />
</project>
+6 -1
View File
@@ -1,7 +1,12 @@
Lombok Changelog
----------------
### v1.18.35 "Edgy Guinea Pig"
### v1.18.37 "Edgy Guinea Pig"
* PLATFORM: JDK24 support added.
* FEATURE: Lombok's nullity annotation now supports [JSpecify](https://jspecify.dev) out of the box, using [config key](https://projectlombok.org/features/configuration) `jspecify`.
* BUGFIX: Recent eclipse releases would get you 'negative length' error. The bug had always been in lombok but didn't matter until recent releases. [Issue #3823](https://github.com/projectlombok/lombok/issues/3823).
### v1.18.36 (November 15th, 2024)
* PLATFORM: JDK23 support added.
* BUGFIX: Eclipse projects using the `com.pro-crafting.tools:jasperreports-maven-plugin` will now compile.
@@ -1,29 +1,33 @@
package lombok.mapstruct;
import java.lang.reflect.Field;
import javax.lang.model.type.TypeMirror;
import org.mapstruct.ap.spi.AstModifyingAnnotationProcessor;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.type.TypeMirror;
import java.util.List;
/**
* Report to MapStruct that a type is completed when there aren't any Lombok annotations left on it. Lombok annotations
* are removed whenever a class is processed. This way, annotations which require multiple rounds to process are also
* correctly handled, and MapStruct processing will be delayed until Lombok completely finishes processing required types.
*/
class NotifierHider {
public static class AstModificationNotifier implements AstModifyingAnnotationProcessor {
@Override
public boolean isTypeComplete(TypeMirror typeMirror) {
private static Field lombokInvoked;
@Override public boolean isTypeComplete(TypeMirror type) {
if (System.getProperty("lombok.disable") != null) return true;
List<? extends AnnotationMirror> annotationMirrors = typeMirror.getAnnotationMirrors();
if (annotationMirrors == null || annotationMirrors.isEmpty()) return true;
for (AnnotationMirror annotationMirror : annotationMirrors) {
String annotationName = String.valueOf(annotationMirror);
if (annotationName.startsWith("@lombok.")) return false;
return isLombokInvoked();
}
private static boolean isLombokInvoked() {
if (lombokInvoked != null) {
try {
return lombokInvoked.getBoolean(null);
} catch (Exception e) {}
return true;
}
try {
Class<?> data = Class.forName("lombok.launch.AnnotationProcessorHider$AstModificationNotifierData");
lombokInvoked = data.getField("lombokInvoked");
return lombokInvoked.getBoolean(null);
} catch (Exception e) {}
return true;
}
}
+2 -1
View File
@@ -106,7 +106,7 @@ public class ConfigurationKeys {
public static final ConfigurationKey<Boolean> ADD_SUPPRESSWARNINGS_ANNOTATIONS = new ConfigurationKey<Boolean>("lombok.addSuppressWarnings", "Generate @java.lang.SuppressWarnings(\"all\") on all generated code (default: true).") {};
/**
* lombok configuration: {@code lombok.addNullAnnotations = }one of: [{@code none}, {@code javax}, {@code eclipse}, {@code jetbrains}, {@code netbeans}, {@code androidx}, {@code android.support}, {@code checkerframework}, {@code findbugs}, {@code spring}, {@code JML}, or a custom set of fully qualified annotation types].
* lombok configuration: {@code lombok.addNullAnnotations = }one of: [{@code none}, {@code javax}, {@code eclipse}, {@code jetbrains}, {@code netbeans}, {@code androidx}, {@code android.support}, {@code checkerframework}, {@code findbugs}, {@code spring}, {@code JML}, {@code jspecify} or a custom set of fully qualified annotation types].
*
* Lombok generally copies relevant nullity annotations from your source code to the right places. However, sometimes lombok generates code where the nullability of some node is not dependent on something in your source code. You can configure lombok to add an appropriate nullity annotation in this case.<ul>
* <li>{@code none} (the default) - no annotations are added.</li>
@@ -121,6 +121,7 @@ public class ConfigurationKeys {
* <li>{@code findbugs} - The annotations {@code edu.umd.cs.findbugs.annotations.NonNull} and {@code edu.umd.cs.findbugs.annotations.Nullable} are used.</li>
* <li>{@code spring} - The annotations {@code org.springframework.lang.NonNull} and {@code org.springframework.lang.Nullable} are used.</li>
* <li>{@code jml} - The annotations {@code org.jmlspecs.annotation.NonNull} and {@code org.jmlspecs.annotation.Nullable} are used.</li>
* <li>{@code jspecify} - The annotations {@code org.jspecify.annotations.NonNull} and {@code org.jspecify.annotations.Nullable} are used.</li>
* <li><code>CUSTOM:<em>fully.qualified.nonnull.annotation</em>:<em>fully.qualified.nullable.annotation</em></code> to configure your own types; the nullable annotation (and the colon) are optional.</li>
* </ul>
* <p>
+1 -1
View File
@@ -30,7 +30,7 @@ public class Version {
// ** CAREFUL ** - this class must always compile with 0 dependencies (it must not refer to any other sources or libraries).
// Note: In 'X.Y.Z', if Z is odd, its a snapshot build built from the repository, so many different 0.10.3 versions can exist, for example.
// Official builds always end in an even number. (Since 0.10.2).
private static final String VERSION = "1.18.35";
private static final String VERSION = "1.18.37";
private static final String RELEASE_NAME = "Edgy Guinea Pig";
// private static final String RELEASE_NAME = "Envious Ferret";
@@ -73,7 +73,8 @@ public final class NullAnnotationLibrary implements ConfigurationValueType {
public static final NullAnnotationLibrary FINDBUGS = new NullAnnotationLibrary("findbugs", "edu.umd.cs.findbugs.annotations.NonNull", "edu.umd.cs.findbugs.annotations.Nullable", false);
public static final NullAnnotationLibrary SPRING = new NullAnnotationLibrary("spring", "org.springframework.lang.NonNull", "org.springframework.lang.Nullable", false);
public static final NullAnnotationLibrary JML = new NullAnnotationLibrary("jml", "org.jmlspecs.annotation.NonNull", "org.jmlspecs.annotation.Nullable", false);
public static final NullAnnotationLibrary JSPECIFY = new NullAnnotationLibrary("jspecify", "org.jspecify.annotations.NonNull", "org.jspecify.annotations.Nullable", true);
private static final List<NullAnnotationLibrary> ALL_AVAILABLE;
private static final String EXAMPLE_VALUE;
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013-2024 The Project Lombok Authors.
* Copyright (C) 2013-2025 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -938,7 +938,7 @@ public class HandlerUtil {
private Pattern pattern;
JavadocTag(String regexpFragment) {
pattern = Pattern.compile("\\s?^[ \\t]*\\**[ \\t]*" + regexpFragment + "(\\S|\\s)*?(?=(\\s^\\s*\\**\\s*@|\\Z))", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);
pattern = Pattern.compile("\\s?^[ \\t]*\\**[ \\t]*" + regexpFragment + ".*?(?=(\\s^\\s*\\**\\s*@|\\Z))", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
}
}
@@ -1010,7 +1010,7 @@ public class HandlerUtil {
public static String getParamJavadoc(String methodComment, String param) {
if (methodComment == null || methodComment.isEmpty()) return methodComment;
Pattern pattern = Pattern.compile("@param " + param + " (\\S|\\s)+?(?=^ ?@|\\z)", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);
Pattern pattern = Pattern.compile("@param " + param + " .+?(?=^ ?@|\\z)", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
Matcher matcher = pattern.matcher(methodComment);
if (matcher.find()) {
return matcher.group();
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2024 The Project Lombok Authors.
* Copyright (C) 2009-2025 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -2156,7 +2156,7 @@ public class EclipseHandlerUtil {
for (int i = 0; i < args.length; i++) {
args[i].sourceStart = pS;
args[i].sourceEnd = pE;
na.memberValuePairs[i] = (MemberValuePair) args[i];
na.memberValuePairs[i] = (MemberValuePair) args[i];
}
setGeneratedBy(na.memberValuePairs[0], source);
setGeneratedBy(na.memberValuePairs[0].value, source);
@@ -2749,10 +2749,8 @@ public class EclipseHandlerUtil {
* Returns {@code true} if the provided node is a record declaration (so, not an annotation definition, interface, enum, or plain class).
*/
public static boolean isRecord(EclipseNode typeNode) {
TypeDeclaration typeDecl = null;
if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get();
int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
return (modifiers & AccRecord) != 0;
ASTNode node = typeNode.get();
return node instanceof TypeDeclaration && isRecord((TypeDeclaration) node);
}
/**
@@ -2786,6 +2784,14 @@ public class EclipseHandlerUtil {
return typeNode.isStatic() || typeNode.up() == null || typeNode.up().getKind() == Kind.COMPILATION_UNIT || isRecord(typeNode);
}
/**
* Returns {@code true} if the provided type declaration is a record declaration (so, not an annotation definition, interface, enum, or plain class).
*/
public static boolean isRecord(TypeDeclaration typeDecl) {
int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
return (modifiers & AccRecord) != 0;
}
public static AbstractVariableDeclaration[] getRecordComponents(TypeDeclaration typeDeclaration) {
if (typeDeclaration == null || (typeDeclaration.modifiers & AccRecord) == 0) return null;
try {
@@ -2812,8 +2818,8 @@ public class EclipseHandlerUtil {
return annotations;
}
private static final Pattern JAVADOC_PATTERN = Pattern.compile("^\\s*\\/\\*\\*((?:\\S|\\s)*?)\\*\\/", Pattern.MULTILINE);
private static final Pattern LEADING_ASTERISKS_PATTERN = Pattern.compile("(?m)^\\s*\\* ?");
private static final Pattern JAVADOC_PATTERN = Pattern.compile("^\\s*\\/\\*\\*(.*?)\\*\\/", Pattern.MULTILINE | Pattern.DOTALL);
private static final Pattern LEADING_ASTERISKS_PATTERN = Pattern.compile("^\\s*\\* ?", Pattern.MULTILINE);
public static String getDocComment(EclipseNode eclipseNode) {
if (eclipseNode.getAst().getSource() == null) return null;
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013-2024 The Project Lombok Authors.
* Copyright (C) 2013-2025 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -59,7 +59,6 @@ import org.eclipse.jdt.internal.compiler.ast.QualifiedThisReference;
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.Receiver;
import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.Statement;
@@ -778,27 +777,23 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
if (mandatories.size() == 0) return null;
int pS = job.source.sourceStart, pE = job.source.sourceEnd;
char[][] nameCalled = fromQualifiedName(CheckerFrameworkVersion.NAME__CALLED);
SingleMemberAnnotation ann = new SingleMemberAnnotation(new QualifiedTypeReference(nameCalled, poss(job.source, nameCalled.length)), pS);
Expression memberValue;
if (mandatories.size() == 1) {
ann.memberValue = new StringLiteral(mandatories.get(0), 0, 0, 0);
memberValue = new StringLiteral(mandatories.get(0), 0, 0, 0);
} else {
ArrayInitializer arr = new ArrayInitializer();
arr.sourceStart = pS;
arr.sourceEnd = pE;
arr.expressions = new Expression[mandatories.size()];
for (int i = 0; i < arr.expressions.length; i++) {
arr.expressions[i] = new StringLiteral(mandatories.get(i), pS, pE, 0);
arr.expressions[i] = new StringLiteral(mandatories.get(i), job.source.sourceStart, job.source.sourceEnd, 0);
}
ann.memberValue = arr;
memberValue = arr;
}
TypeReference typeReference = job.createBuilderTypeReference();
int len = typeReference.getTypeName().length;
typeReference.annotations = new Annotation[len][];
typeReference.annotations[len - 1] = new Annotation[] {ann};
typeReference.annotations[len - 1] = EclipseHandlerUtil.addAnnotation(job.source, null, nameCalled, memberValue);
return new Receiver(new char[] { 't', 'h', 'i', 's' }, 0, typeReference, null, 0);
}
@@ -364,7 +364,7 @@ public class HandleConstructor {
if (addConstructorProperties && !isLocalType(typeNode) && LombokOptionsFactory.getDelombokOptions(typeNode.getContext()).getFormatPreferences().generateConstructorProperties()) {
addConstructorProperties(mods, typeNode, fieldsToParam);
}
if (onConstructor != null) mods.annotations = mods.annotations.appendList(copyAnnotations(onConstructor));
if (onConstructor != null) mods.annotations = mods.annotations.appendList(copyAnnotations(onConstructor, maker));
return recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("<init>"),
null, List.<JCTypeParameter>nil(), params.toList(), List.<JCExpression>nil(),
maker.Block(0L, nullChecks.appendList(assigns).toList()), null), source);
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2021 The Project Lombok Authors.
* Copyright (C) 2009-2025 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -185,12 +185,12 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
}
}
JCMethodDecl equalsMethod = createEquals(typeNode, members, callSuper, fieldAccess, needsCanEqual, source, onParam);
JCMethodDecl equalsMethod = createEquals(typeNode, members, callSuper, fieldAccess, needsCanEqual, source, copyAnnotations(onParam, typeNode.getTreeMaker()));
injectMethod(typeNode, equalsMethod);
if (needsCanEqual && canEqualExists == MemberExistsResult.NOT_EXISTS) {
JCMethodDecl canEqualMethod = createCanEqual(typeNode, source, copyAnnotations(onParam));
JCMethodDecl canEqualMethod = createCanEqual(typeNode, source, copyAnnotations(onParam, typeNode.getTreeMaker()));
injectMethod(typeNode, canEqualMethod);
}
@@ -252,10 +252,10 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> {
JCExpression annotationMethodDefaultValue = null;
List<JCAnnotation> copyableAnnotations = findCopyableAnnotations(field);
List<JCAnnotation> copyableToGetterAnnotations = copyAnnotations(findCopyableToGetterAnnotations(field));
List<JCAnnotation> copyableToGetterAnnotations = copyAnnotations(findCopyableToGetterAnnotations(field), treeMaker);
List<JCAnnotation> delegates = findDelegatesAndRemoveFromField(field);
List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod).appendList(copyableAnnotations).appendList(copyableToGetterAnnotations);
List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod, treeMaker).appendList(copyableAnnotations).appendList(copyableToGetterAnnotations);
if (field.isFinal()) {
if (getCheckerFrameworkVersion(field).generatePure()) annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(genTypeRef(field, CheckerFrameworkVersion.NAME__PURE), List.<JCExpression>nil()));
} else {
@@ -181,7 +181,7 @@ public class HandleJacksonized extends JavacAnnotationHandler<Jacksonized> {
// Copy annotations from the class to the builder class.
List<JCAnnotation> copyableAnnotations = findJacksonAnnotationsOnClass(tdNode);
List<JCAnnotation> copiedAnnotations = copyAnnotations(copyableAnnotations);
List<JCAnnotation> copiedAnnotations = copyAnnotations(copyableAnnotations, maker);
for (JCAnnotation anno : copiedAnnotations) {
recursiveSetGeneratedBy(anno, annotationNode);
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010-2021 The Project Lombok Authors.
* Copyright (C) 2010-2025 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -43,7 +43,6 @@ import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCLiteral;
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.util.List;
@@ -156,11 +155,9 @@ public class HandleLog {
expressions[i] = maker.Apply(List.<JCExpression>nil(), method, List.<JCExpression>nil());
break;
case TOPIC:
if (loggerTopic instanceof JCLiteral) {
expressions[i] = maker.Literal(((JCLiteral) loggerTopic).value);
} else {
expressions[i] = cloneType(maker, loggerTopic, typeNode);
}
JCExpression topicExpression = copyExpression(loggerTopic, maker);
recursiveSetGeneratedBy(topicExpression, typeNode);
expressions[i] = topicExpression;
break;
case NULL:
expressions[i] = maker.Literal(CTC_BOT, null);
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013-2021 The Project Lombok Authors.
* Copyright (C) 2013-2025 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -94,17 +94,17 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> {
JCModifiers mods = maker.Modifiers(toJavacModifier(AccessLevel.PUBLIC) | COMPACT_RECORD_CONSTRUCTOR, List.<JCAnnotation>nil());
JCBlock body = maker.Block(0L, List.<JCStatement>nil());
if (existingCtr == null) {
JCMethodDecl constr = maker.MethodDef(mods, typeNode.toName("<init>"), null, List.<JCTypeParameter>nil(), params.toList(), List.<JCExpression>nil(), body, null);
return recursiveSetGeneratedBy(constr, source);
JCMethodDecl constuctor = existingCtr;
if (constuctor == null) {
constuctor = maker.MethodDef(mods, typeNode.toName("<init>"), null, List.<JCTypeParameter>nil(), params.toList(), List.<JCExpression>nil(), body, null);
} else {
existingCtr.mods = mods;
existingCtr.body = body;
existingCtr = recursiveSetGeneratedBy(existingCtr, source);
addSuppressWarningsAll(existingCtr.mods, typeNode, typeNode.getNodeFor(getGeneratedBy(existingCtr)), typeNode.getContext());
addGenerated(existingCtr.mods, typeNode, typeNode.getNodeFor(getGeneratedBy(existingCtr)), typeNode.getContext());
return existingCtr;
constuctor.mods = mods;
constuctor.body = body;
}
recursiveSetGeneratedBy(constuctor, source);
addSuppressWarningsAll(constuctor.mods, typeNode, source, typeNode.getContext());
addGenerated(constuctor.mods, typeNode, source, typeNode.getContext());
return constuctor;
}
/**
@@ -132,7 +132,6 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> {
if (md.name.contentEquals("<init>")) {
if ((md.mods.flags & Flags.GENERATEDCONSTR) != 0) {
existingCtr = md;
existingCtr.mods.flags = existingCtr.mods.flags & ~Flags.GENERATEDCONSTR;
generateConstructor = true;
} else {
if (!isTolerate(typeNode, md)) {
@@ -307,7 +306,7 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> {
if (invocation.args.isEmpty()) return null;
JCExpression firstArgument = invocation.args.head;
if (!(firstArgument instanceof JCIdent)) return null;
return ((JCIdent) firstArgument).toString();
return firstArgument.toString();
}
if (isIf) {
@@ -245,7 +245,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> {
List<JCAnnotation> copyableAnnotations = findCopyableAnnotations(field);
Name methodName = field.toName(setterName);
List<JCAnnotation> annsOnParam = copyAnnotations(onParam).appendList(copyableAnnotations);
List<JCAnnotation> annsOnParam = copyAnnotations(onParam, treeMaker).appendList(copyableAnnotations);
long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, field.getContext());
JCExpression pType = cloneType(treeMaker, fieldDecl.vartype, source);
@@ -284,7 +284,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> {
Boolean fluentConfig = field.getAst().readConfiguration(ConfigurationKeys.ACCESSORS_FLUENT);
if (fluentConfig != null && fluentConfig) fluent = fluentConfig;
List<JCAnnotation> annsOnMethod = mergeAnnotations(copyAnnotations(onMethod), findCopyableToSetterAnnotations(field, fluent));
List<JCAnnotation> annsOnMethod = mergeAnnotations(copyAnnotations(onMethod, treeMaker), findCopyableToSetterAnnotations(field, fluent));
if (isFieldDeprecated(field) || deprecate) {
annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.<JCExpression>nil()));
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015-2021 The Project Lombok Authors.
* Copyright (C) 2015-2024 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -107,7 +107,7 @@ public class HandleUtilityClass extends JavacAnnotationHandler<UtilityClass> {
if ((typeDecl.mods.flags & (Flags.INTERFACE | Flags.ANNOTATION)) != 0) markStatic = false;
}
if (markStatic) classDecl.mods.flags |= Flags.STATIC;
if (markStatic) markClassAsStatic(classDecl);
for (JavacNode element : typeNode.down()) {
if (element.getKind() == Kind.FIELD) {
@@ -125,21 +125,23 @@ public class HandleUtilityClass extends JavacAnnotationHandler<UtilityClass> {
methodDecl.mods.flags |= Flags.STATIC;
} else if (element.getKind() == Kind.TYPE) {
JCClassDecl innerClassDecl = (JCClassDecl) element.get();
innerClassDecl.mods.flags |= Flags.STATIC;
ClassSymbol innerClassSymbol = innerClassDecl.sym;
if (innerClassSymbol != null) {
if (innerClassSymbol.type instanceof ClassType) {
((ClassType) innerClassSymbol.type).setEnclosingType(Type.noType);
}
innerClassSymbol.erasure_field = null;
}
markClassAsStatic((JCClassDecl) element.get());
}
}
if (makeConstructor) createPrivateDefaultConstructor(typeNode);
}
private void markClassAsStatic(JCClassDecl classDecl) {
classDecl.mods.flags |= Flags.STATIC; // maybe Flags.NOOUTERTHIS too?
ClassSymbol innerClassSymbol = classDecl.sym;
if (innerClassSymbol != null && innerClassSymbol.type instanceof ClassType) {
ClassType classType = (ClassType) innerClassSymbol.type;
classType.setEnclosingType(Type.noType);
innerClassSymbol.erasure_field = null;
}
}
private void createPrivateDefaultConstructor(JavacNode typeNode) {
JavacTreeMaker maker = typeNode.getTreeMaker();
JCModifiers mods = maker.Modifiers(Flags.PRIVATE, List.<JCAnnotation>nil());
@@ -229,7 +229,7 @@ public class HandleWith extends JavacAnnotationHandler<With> {
JCBlock methodBody = null;
long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, field.getContext());
List<JCAnnotation> annsOnParam = copyAnnotations(onParam).appendList(copyableAnnotations);
List<JCAnnotation> annsOnParam = copyAnnotations(onParam, maker).appendList(copyableAnnotations);
JCExpression pType = cloneType(maker, fieldDecl.vartype, source);
JCVariableDecl param = maker.VarDef(maker.Modifiers(flags, annsOnParam), fieldDecl.name, pType, null);
@@ -278,7 +278,7 @@ public class HandleWith extends JavacAnnotationHandler<With> {
List<JCExpression> throwsClauses = List.nil();
JCExpression annotationMethodDefaultValue = null;
List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod);
List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod, maker);
CheckerFrameworkVersion checkerFramework = getCheckerFrameworkVersion(source);
if (checkerFramework.generateSideEffectFree()) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil()));
@@ -321,7 +321,7 @@ public class HandleWithBy extends JavacAnnotationHandler<WithBy> {
List<JCExpression> throwsClauses = List.nil();
JCExpression annotationMethodDefaultValue = null;
List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod);
List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod, maker);
CheckerFrameworkVersion checkerFramework = getCheckerFrameworkVersion(source);
if (checkerFramework.generateSideEffectFree()) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil()));
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2022 The Project Lombok Authors.
* Copyright (C) 2009-2025 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -37,6 +37,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import com.sun.source.tree.TreeVisitor;
import com.sun.tools.javac.code.Attribute;
import com.sun.tools.javac.code.BoundKind;
import com.sun.tools.javac.code.Flags;
@@ -74,6 +75,7 @@ import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.JCTree.JCWildcard;
import com.sun.tools.javac.tree.JCTree.TypeBoundKind;
import com.sun.tools.javac.tree.TreeCopier;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.TreeScanner;
import com.sun.tools.javac.util.Context;
@@ -590,38 +592,42 @@ public class JavacHandlerUtil {
private static final Field astField;
private static final Field originalAnnos;
private static final Method findRecordComponentToRemove;
private static final Method getRecordComponents = Permit.permissiveGetMethod(ClassSymbol.class, "getRecordComponents");
static {
Field a = null;
Field o = null;
Method m = null;
try {
Class<?> forName = Class.forName("com.sun.tools.javac.code.Symbol$RecordComponent");
a = Permit.permissiveGetField(forName, "ast");
o = Permit.permissiveGetField(forName, "originalAnnos");
m = Permit.permissiveGetMethod(ClassSymbol.class, "findRecordComponentToRemove", JCVariableDecl.class);
} catch (Throwable e) {
// Ignore
}
astField = a;
originalAnnos = o;
findRecordComponentToRemove = m;
}
static void deleteAnnotation(JCClassDecl record, JCVariableDecl component, JCTree annotation) {
if ((astField == null && originalAnnos == null) || findRecordComponentToRemove == null) return;
if ((astField == null && originalAnnos == null) || getRecordComponents == null) return;
try {
Object toRemove = Permit.invokeSneaky(findRecordComponentToRemove, record.sym, component);
if (astField != null) {
// OpenJDK
JCVariableDecl variable = Permit.get(astField, toRemove);
variable.mods.annotations = filterListByPos(variable.mods.annotations, annotation);
} else {
// Zulu JDK 17
List<JCAnnotation> annotations = Permit.get(originalAnnos, toRemove);
Permit.set(originalAnnos, toRemove, filterListByPos(annotations, annotation));
List<?> recordComponents = (List<?>) Permit.invokeSneaky(getRecordComponents, record.sym);
for (Object recordComponent : recordComponents) {
Name recordComponentName = ((Symbol) recordComponent).name;
if (!recordComponentName.equals(component.name)) continue;
if (astField != null) {
// OpenJDK
JCVariableDecl variable = Permit.get(astField, recordComponent);
variable.mods.annotations = filterListByPos(variable.mods.annotations, annotation);
} else {
// Zulu JDK 17
List<JCAnnotation> annotations = Permit.get(originalAnnos, recordComponent);
Permit.set(originalAnnos, recordComponent, filterListByPos(annotations, annotation));
}
return;
}
} catch (Throwable e) {
// Ignore
@@ -1746,7 +1752,8 @@ public class JavacHandlerUtil {
}
}
}
return copyAnnotations(result.toList());
return copyAnnotations(result.toList(), node.getTreeMaker());
}
/**
@@ -1797,7 +1804,7 @@ public class JavacHandlerUtil {
if (annoName == null) return List.nil();
if (!annoName.isEmpty()) {
for (String bn : annotationsToFind) if (typeMatches(bn, node, annoName)) return copyAnnotations(List.of(anno));
for (String bn : annotationsToFind) if (typeMatches(bn, node, annoName)) return copyAnnotations(List.of(anno), node.getTreeMaker());
}
ListBuffer<JCAnnotation> result = new ListBuffer<JCAnnotation>();
@@ -1812,7 +1819,7 @@ public class JavacHandlerUtil {
}
}
}
return copyAnnotations(result.toList());
return copyAnnotations(result.toList(), node.getTreeMaker());
}
/**
@@ -2121,15 +2128,21 @@ public class JavacHandlerUtil {
errorNode.addError(out.append(" are not allowed on builder classes.").toString());
}
static List<JCAnnotation> copyAnnotations(List<? extends JCExpression> in) {
static List<JCAnnotation> copyAnnotations(List<? extends JCExpression> in, JavacTreeMaker maker) {
ListBuffer<JCAnnotation> out = new ListBuffer<JCAnnotation>();
for (JCExpression expr : in) {
if (!(expr instanceof JCAnnotation)) continue;
out.append((JCAnnotation) expr.clone());
out.append(copyExpression((JCAnnotation) expr, maker));
}
return out.toList();
}
@SuppressWarnings("unchecked")
static <T extends JCExpression> T copyExpression(T expression, JavacTreeMaker maker) {
TreeVisitor<JCTree, Void> visitor = new TreeCopier<Void>(maker.getUnderlyingTreeMaker());
return (T) expression.accept(visitor, null);
}
static List<JCAnnotation> mergeAnnotations(List<JCAnnotation> a, List<JCAnnotation> b) {
if (a == null || a.isEmpty()) return b;
if (b == null || b.isEmpty()) return a;
@@ -2279,7 +2292,7 @@ public class JavacHandlerUtil {
if (JCAnnotatedTypeReflect.is(in)) {
JCExpression underlyingType = cloneType0(maker, JCAnnotatedTypeReflect.getUnderlyingType(in));
List<JCAnnotation> anns = copyAnnotations(JCAnnotatedTypeReflect.getAnnotations(in));
List<JCAnnotation> anns = copyAnnotations(JCAnnotatedTypeReflect.getAnnotations(in), maker);
return JCAnnotatedTypeReflect.create(anns, underlyingType);
}
@@ -315,7 +315,7 @@ public class JavacSingularsRecipes {
if (!setterPrefix.isEmpty()) name = builderType.toName(HandlerUtil.buildAccessorName(source, setterPrefix, name.toString()));
statements.prepend(createConstructBuilderVarIfNeeded(maker, data, builderType, source));
List<JCAnnotation> methodAnnotations = copyAnnotations(findCopyableToBuilderSingularSetterAnnotations(data.annotation.up()));
List<JCAnnotation> methodAnnotations = copyAnnotations(findCopyableToBuilderSingularSetterAnnotations(data.annotation.up()), maker);
finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, params, methodAnnotations, access, null);
}
@@ -362,7 +362,7 @@ public class JavacSingularsRecipes {
statements.prepend(JavacHandlerUtil.generateNullCheck(maker, null, data.getPluralName(), builderType, "%s cannot be null"));
}
List<JCAnnotation> methodAnnotations = copyAnnotations(findCopyableToSetterAnnotations(data.annotation.up(), true));
List<JCAnnotation> methodAnnotations = copyAnnotations(findCopyableToSetterAnnotations(data.annotation.up(), true), maker);
finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, List.of(param), methodAnnotations, access, ignoreNullCollections);
}
@@ -103,6 +103,7 @@ public class Delombok {
private LinkedHashMap<File, File> fileToBase = new LinkedHashMap<File, File>();
private List<File> filesToParse = new ArrayList<File>();
private Map<String, String> formatPrefs = new HashMap<String, String>();
private List<AbstractProcessor> preLombokProcessors = new ArrayList<AbstractProcessor>();
private List<AbstractProcessor> additionalAnnotationProcessors = new ArrayList<AbstractProcessor>();
/** If null, output to standard out. */
@@ -653,6 +654,10 @@ public class Delombok {
fileToBase.put(f, base);
}
public void addPreLombokProcessors(AbstractProcessor processor) {
preLombokProcessors.add(processor);
}
public void addAdditionalAnnotationProcessor(AbstractProcessor processor) {
additionalAnnotationProcessors.add(processor);
}
@@ -735,6 +740,7 @@ public class Delombok {
Map<JCCompilationUnit, File> baseMap = new IdentityHashMap<JCCompilationUnit, File>();
Set<AbstractProcessor> processors = new LinkedHashSet<AbstractProcessor>();
processors.addAll(preLombokProcessors);
processors.add(new lombok.javac.apt.LombokProcessor());
processors.addAll(additionalAnnotationProcessors);
@@ -96,6 +96,7 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable {
patchSyntaxAndOccurrencesHighlighting(sm);
patchSortMembersOperation(sm);
patchExtractInterfaceAndPullUp(sm);
patchExtractVariable(sm);
patchAboutDialog(sm);
patchEclipseDebugPatches(sm);
patchJavadoc(sm);
@@ -225,6 +226,17 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable {
.build());
}
private static void patchExtractVariable(ScriptManager sm) {
/* Fix sourceEnding for generated nodes to avoid null pointer */
sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.replaceMethodCall()
.target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.util.SideEffectChecker", "findFunctionDefinition", "org.eclipse.jdt.core.dom.MethodDeclaration", "org.eclipse.jdt.core.dom.ITypeBinding", "org.eclipse.jdt.core.dom.IMethodBinding"))
.methodToReplace(new Hook("org.eclipse.jdt.core.dom.NodeFinder", "perform", "org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.jdt.core.ISourceRange"))
.replacementMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "findGeneratedNode", "org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.jdt.core.ISourceRange", "org.eclipse.jdt.core.dom.IMethodBinding"))
.requestExtra(StackRequest.PARAM2)
.transplant()
.build());
}
private static void patchInline(ScriptManager sm) {
sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapReturnValue()
.target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.code.SourceProvider", "getCodeBlocks", "java.lang.String[]", "org.eclipse.jdt.internal.corext.refactoring.code.CallContext", "org.eclipse.jdt.core.dom.rewrite.ImportRewrite"))
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010-2024 The Project Lombok Authors.
* Copyright (C) 2010-2025 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -48,13 +48,13 @@ import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.FieldReference;
import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
@@ -129,7 +129,8 @@ public class PatchDelegate {
}
private static boolean hasDelegateMarkedFieldsOrMethods(TypeDeclaration decl) {
if (decl.fields != null) for (FieldDeclaration field : decl.fields) {
AbstractVariableDeclaration[] fields = getFieldsOrRecordComponents(decl);
if (fields != null) for (AbstractVariableDeclaration field : fields) {
if (field.annotations == null) continue;
for (Annotation ann : field.annotations) {
if (isDelegate(ann, decl)) return true;
@@ -224,11 +225,19 @@ public class PatchDelegate {
Annotation_applied.set(annotation, true);
}
private static AbstractVariableDeclaration[] getFieldsOrRecordComponents(TypeDeclaration decl) {
if (isRecord(decl)) return getRecordComponents(decl);
return decl.fields;
}
private static void fillMethodBindingsForFields(CompilationUnitDeclaration cud, ClassScope scope, List<BindingTuple> methodsToDelegate) {
TypeDeclaration decl = scope.referenceContext;
if (decl == null) return;
if (decl.fields != null) for (FieldDeclaration field : decl.fields) {
AbstractVariableDeclaration[] fields = getFieldsOrRecordComponents(decl);
if (fields == null) return;
for (AbstractVariableDeclaration field : fields) {
if (field.annotations == null) continue;
for (Annotation ann : field.annotations) {
if (!isDelegate(ann, decl)) continue;
@@ -41,12 +41,16 @@ import org.eclipse.jdt.core.IAnnotatable;
import org.eclipse.jdt.core.IAnnotation;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.NodeFinder;
import org.eclipse.jdt.core.dom.ReturnStatement;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
@@ -951,6 +955,16 @@ final class PatchFixesHider {
return blocks;
}
}
public static ASTNode findGeneratedNode(ASTNode root, ISourceRange sourceRange, IMethodBinding methodBinding) {
ASTNode result = NodeFinder.perform(root, sourceRange);
if (result instanceof MethodDeclaration){
return result;
}
CompilationUnit cu = (CompilationUnit) root;
return cu.findDeclaringNode(methodBinding.getKey());
}
}
public static class FieldInitializer {
@@ -39,6 +39,10 @@ import sun.misc.Unsafe;
class AnnotationProcessorHider {
public static class AstModificationNotifierData {
public volatile static boolean lombokInvoked = false;
}
public static class AnnotationProcessor extends AbstractProcessor {
private final AbstractProcessor instance = createWrappedInstance();
@@ -56,6 +60,7 @@ class AnnotationProcessorHider {
@Override public void init(ProcessingEnvironment processingEnv) {
disableJava9SillyWarning();
AstModificationNotifierData.lombokInvoked = true;
instance.init(processingEnv);
super.init(processingEnv);
}
@@ -1,5 +1,7 @@
package com.sun.tools.javac.parser;
import com.sun.tools.javac.util.JCDiagnostic;
public class Tokens {
public static class Token {
public int pos;
@@ -12,6 +14,8 @@ public class Tokens {
String getText();
JCDiagnostic.DiagnosticPosition getPos();
int getSourcePos(int index);
CommentStyle getStyle();
@@ -0,0 +1,5 @@
package com.sun.tools.javac.util;
public class JCDiagnostic {
public interface DiagnosticPosition {}
}
+10 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2024 The Project Lombok Authors.
* Copyright (C) 2009-2025 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,7 @@
package lombok.javac;
import static lombok.javac.JavacTreeMaker.TreeTag.treeTag;
import static lombok.javac.JavacTreeMaker.TypeTag.typeTag;
import static lombok.javac.JavacTreeMaker.TypeTag.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@@ -55,6 +55,7 @@ import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.JCTree.JCImport;
import com.sun.tools.javac.tree.JCTree.JCLiteral;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.TreeInfo;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import lombok.core.ClassLiteral;
@@ -184,7 +185,8 @@ public class Javac {
public static final TypeTag CTC_NONE = typeTag("NONE");
public static final TypeTag CTC_BOT = typeTag("BOT");
public static final TypeTag CTC_ERROR = typeTag("ERROR");
public static final TypeTag CTC_UNKNOWN = typeTag("UNKNOWN");
public static final TypeTag CTC_UNKNOWN = typeTagPermissive("UNKNOWN"); // UNKNOWN has been removed in JDK24, hence, we need to look it up permissively (just make it `null` if it does not exist).
public static final TypeTag CTC_UNDETVAR = typeTag("UNDETVAR");
public static final TypeTag CTC_CLASS = typeTag("CLASS");
@@ -381,6 +383,10 @@ public class Javac {
@Override public boolean isDeprecated() {
return text.contains("@deprecated") && field instanceof JCVariableDecl && isFieldDeprecated(field);
}
@Override public DiagnosticPosition getPos() {
return field;
}
};
}
}
@@ -416,7 +422,7 @@ public class Javac {
throw sneakyThrow(e.getCause());
}
}
public static void storeEnd(JCTree tree, int pos, JCCompilationUnit top) {
try {
Object endPositions = JCCOMPILATIONUNIT_ENDPOSITIONS.get(top);
+10 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013-2020 The Project Lombok Authors.
* Copyright (C) 2013-2025 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -258,6 +258,15 @@ public class JavacTreeMaker {
public static TypeTag typeTag(String identifier) {
return new TypeTag(getFieldCached(TYPE_TAG_CACHE, Javac.getJavaCompilerVersion() < 8 ? "com.sun.tools.javac.code.TypeTags" : "com.sun.tools.javac.code.TypeTag", identifier));
}
public static TypeTag typeTagPermissive(String identifier) {
try {
return typeTag(identifier);
} catch (Exception e) {
if (e instanceof NoSuchFieldException) return null;
throw Javac.sneakyThrow(e);
}
}
}
public static class TreeTag extends SchroedingerType {
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010-2021 The Project Lombok Authors.
* Copyright (C) 2010-2025 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -105,7 +105,7 @@ public class TreeMirrorMaker extends TreeCopier<Void> {
boolean wipeSymAndType = copy.type.isErroneous();
if (!wipeSymAndType) {
TypeTag typeTag = TypeTag.typeTag(copy.type);
wipeSymAndType = (CTC_NONE.equals(typeTag) || CTC_ERROR.equals(typeTag) || CTC_UNKNOWN.equals(typeTag) || CTC_UNDETVAR.equals(typeTag));
wipeSymAndType = (typeTag.equals(CTC_NONE) || typeTag.equals(CTC_ERROR) || typeTag.equals(CTC_UNKNOWN) || typeTag.equals(CTC_UNDETVAR));
}
if (wipeSymAndType) {
+5 -6
View File
@@ -132,16 +132,15 @@ public class Permit {
public static Field getField(Class<?> c, String fName) throws NoSuchFieldException {
Field f = null;
Class<?> oc = c;
while (c != null) {
Class<?> d = c;
while (d != null) {
try {
f = c.getDeclaredField(fName);
f = d.getDeclaredField(fName);
break;
} catch (NoSuchFieldException e) {}
c = c.getSuperclass();
d = d.getSuperclass();
}
if (f == null) throw new NoSuchFieldException(oc.getName() + " :: " + fName);
if (f == null) throw new NoSuchFieldException(c.getName() + " :: " + fName);
return setAccessible(f);
}
+36 -14
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2024 The Project Lombok Authors.
* Copyright (C) 2009-2025 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -33,6 +33,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Locale;
@@ -83,7 +84,11 @@ public class RunTestsViaDelombok extends AbstractRunTests {
delombok.setDiagnosticsListener(new CapturingDiagnosticListener(file, result.getMessages()));
if (parameters.isCheckPositions()) delombok.addAdditionalAnnotationProcessor(new ValidatePositionProcessor(parameters.getMinVersion()));
if (parameters.isCheckPositions()) {
NodePositionMapper nodePositionMapper = new NodePositionMapper();
delombok.addPreLombokProcessors(nodePositionMapper);
delombok.addAdditionalAnnotationProcessor(new ValidatePositionProcessor(parameters.getMinVersion(), nodePositionMapper));
}
delombok.addAdditionalAnnotationProcessor(new ValidateTypesProcessor());
delombok.addAdditionalAnnotationProcessor(new ValidateNoDuplicateTreeNodeProcessor());
@@ -105,15 +110,36 @@ public class RunTestsViaDelombok extends AbstractRunTests {
}
}
public static class NodePositionMapper extends TreeProcessor {
Map<JCTree, Integer> nodePositions = new HashMap<JCTree, Integer>();
@Override void processCompilationUnit(final JCCompilationUnit unit) {
unit.accept(new TreeScanner() {
@Override public void scan(JCTree tree) {
if (tree == null) return;
if (tree instanceof JCMethodDecl && (((JCMethodDecl) tree).mods.flags & Flags.GENERATEDCONSTR) != 0) return;
if (tree.pos >= 0) {
nodePositions.put(tree, tree.pos);
}
super.scan(tree);
}
});
}
}
public static class ValidatePositionProcessor extends TreeProcessor {
private final int version;
private final NodePositionMapper nodePositionMapper;
public ValidatePositionProcessor(int version) {
public ValidatePositionProcessor(int version, NodePositionMapper nodePositionMapper) {
this.version = version;
this.nodePositionMapper = nodePositionMapper;
}
private String craftFailMsg(String problematicNode, Deque<JCTree> astContext) {
StringBuilder msg = new StringBuilder(problematicNode).append(" position of node not set: ");
StringBuilder msg = new StringBuilder(problematicNode);
for (JCTree t : astContext) {
msg.append("\n ").append(t.getClass().getSimpleName());
String asStr = t.toString();
@@ -153,10 +179,14 @@ public class RunTestsViaDelombok extends AbstractRunTests {
if (tree instanceof JCVariableDecl && (((JCVariableDecl) tree).mods.flags & Javac.GENERATED_MEMBER) != 0) return;
if (check && tree.pos == -1) fail(craftFailMsg("Start", astContext));
if (check && tree.pos == -1) fail(craftFailMsg("Start position of node not set: ", astContext));
Integer expectedPos = nodePositionMapper.nodePositions.get(tree);
if (expectedPos != null && !expectedPos.equals(tree.pos)) {
fail(craftFailMsg(String.format("Expected node position %d, actual node position %d: ", expectedPos, tree.pos), astContext));
}
if (check && Javac.getEndPosition(tree, unit) == -1) {
fail(craftFailMsg("End", astContext));
fail(craftFailMsg("End position of node not set: ", astContext));
}
} finally {
try {
@@ -289,14 +319,6 @@ public class RunTestsViaDelombok extends AbstractRunTests {
super.scan(tree);
parents.pop();
}
/**
* We always generate shallow copies for annotations
*/
@Override
public void visitAnnotation(JCAnnotation tree) {
return;
}
});
}
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010-2024 The Project Lombok Authors.
* Copyright (C) 2010-2025 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -242,7 +242,7 @@ public class RunTestsViaEcj extends AbstractRunTests {
return source;
}
};
return AST.convertCompilationUnit(4, cud, options, false, ccu, 0, null);
return AST.convertCompilationUnit(8, cud, options, false, ccu, 0, null);
}
}
@@ -0,0 +1,15 @@
package pkg;
import java.util.Arrays;
import lombok.Getter;
@Getter
public class A {
private String string;
public List<String> test() {
String temp = getString();
return Arrays.asList(temp, temp, temp);
}
}
@@ -0,0 +1,14 @@
package pkg;
import java.util.Arrays;
import lombok.Getter;
@Getter
public class A {
private String string;
public List<String> test() {
return Arrays.asList(getString(), getString(), getString());
}
}
@@ -0,0 +1,13 @@
package pkg;
import lombok.Getter;
@Getter
public class A {
private String string;
public String test() {
String temp = getString();
return temp;
}
}
@@ -0,0 +1,12 @@
package pkg;
import lombok.Getter;
@Getter
public class A {
private String string;
public String test() {
return getString();
}
}
@@ -31,12 +31,13 @@ import lombok.eclipse.edit.SelectTest;
import lombok.eclipse.misc.DelegateTest;
import lombok.eclipse.misc.JavadocTest;
import lombok.eclipse.refactoring.ExtractInterfaceTest;
import lombok.eclipse.refactoring.ExtractVariableTest;
import lombok.eclipse.refactoring.InlineTest;
import lombok.eclipse.refactoring.RenameTest;
import lombok.eclipse.references.FindReferencesTest;
@RunWith(Suite.class)
@SuiteClasses({ExtractInterfaceTest.class, RenameTest.class, SelectTest.class, CleanupTest.class, FindReferencesTest.class, InlineTest.class, NoErrorsTest.class, JavadocTest.class, DelegateTest.class})
@SuiteClasses({ExtractInterfaceTest.class, RenameTest.class, SelectTest.class, CleanupTest.class, FindReferencesTest.class, InlineTest.class, NoErrorsTest.class, JavadocTest.class, DelegateTest.class, ExtractVariableTest.class})
public class EclipseTests {
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022 The Project Lombok Authors.
* Copyright (C) 2022-2024 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,7 +21,7 @@
*/
package lombok.eclipse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
@@ -45,7 +45,7 @@ public class RefactoringUtils {
ResourcesPlugin.getWorkspace().run(perform, null);
assertTrue("Condition failed", change.getConditionCheckingStatus().isOK());
assertEquals("Condition failed", "<OK\n>", change.getConditionCheckingStatus().toString());
assertTrue("Perform failed", perform.changeExecuted());
}
}
@@ -0,0 +1,65 @@
/*
* Copyright (C) 2024 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package lombok.eclipse.refactoring;
import static lombok.eclipse.RefactoringUtils.performRefactoring;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.internal.corext.refactoring.code.ExtractTempRefactoring;
import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import lombok.eclipse.EclipseRunner;
import lombok.eclipse.SetupBeforeAfterTest;
@RunWith(EclipseRunner.class)
public class ExtractVariableTest {
@Rule
public SetupBeforeAfterTest setup = new SetupBeforeAfterTest();
@Test
public void single() throws Exception {
ICompilationUnit cu = setup.getPackageFragment().getCompilationUnit("A.java");
CompilationUnit compilationUnit = new RefactoringASTParser(ASTProvider.SHARED_AST_LEVEL).parse(cu, true);
ExtractTempRefactoring extractTempRefactoring = new ExtractTempRefactoring(compilationUnit, 121, 11);
extractTempRefactoring.setTempName("temp");
performRefactoring(extractTempRefactoring);
}
@Test
public void multiple() throws Exception {
ICompilationUnit cu = setup.getPackageFragment().getCompilationUnit("A.java");
CompilationUnit compilationUnit = new RefactoringASTParser(ASTProvider.SHARED_AST_LEVEL).parse(cu, true);
ExtractTempRefactoring extractTempRefactoring = new ExtractTempRefactoring(compilationUnit, 167, 11);
extractTempRefactoring.setTempName("temp");
performRefactoring(extractTempRefactoring);
}
}
+1
View File
@@ -0,0 +1 @@
/out
+20
View File
@@ -0,0 +1,20 @@
#!/bin/sh
set -e
echo 'This will compile a selection of files in test/transform/resource/before. If the compilation works without error, lombok is working as designed.'
mkdir -p out/
# list of files to iterate over
FILES="UtilityClassInner.java"
BASE_PATH="../../../test/transform/resource/before"
LOMBOK_JAR="../../../dist/lombok.jar"
# compile all files in list
for f in $FILES
do
echo "Compiling $f"
javac -processorpath $LOMBOK_JAR -cp $LOMBOK_JAR -d out/ $BASE_PATH/$f
done
rm -rf out/
@@ -0,0 +1,8 @@
// version 14:
record DelegateOnRecord(Runnable runnable) {
@java.lang.SuppressWarnings("all")
@lombok.Generated
public void run() {
this.runnable.run();
}
}
@@ -163,3 +163,207 @@ class GetterSetterJavadoc5 {
return this;
}
}
class GetterSetterJavadocLong {
/**
* This field represents the unique identifier for a user in the system. It is used
* throughout the application to uniquely identify and retrieve user-related data.
* The ID is typically generated by the database and is guaranteed to be unique
* within the context of the system.
*
* <p>The ID is an integral part of various operations, including but not limited to:
* <ul>
* <li>Authenticating users during login processes.</li>
* <li>Associating user-specific preferences and settings.</li>
* <li>Tracking user activity and logs for auditing purposes.</li>
* <li>Facilitating relationships between users and other entities such as orders,
* messages, or roles within the system.</li>
* </ul>
*
* <p>Key characteristics of the {@code userId} field:
* <ul>
* <li><strong>Immutability:</strong> Once assigned, the ID must not be modified to
* ensure data integrity.</li>
* <li><strong>Security:</strong> Access to this field should be controlled to prevent
* unauthorized modifications or data leakage.</li>
* <li><strong>Uniqueness:</strong> The ID must be unique within the system. For
* distributed systems, consider using GUIDs or UUIDs to avoid collisions.</li>
* </ul>
*
* <p>Example usage:
* <pre>
* User user = userService.getUserById(userId);
* if (user != null) {
* System.out.println("User found: " + user.getName());
* } else {
* System.out.println("User not found.");
* }
* </pre>
*
* <p>Developers should ensure that the ID complies with constraints imposed by the
* database schema, such as length and format restrictions. Furthermore, it is
* recommended to validate the ID before persisting or using it in critical operations.
*
* <p>For methods or constructors that accept the {@code userId} as a parameter, the
* following guidelines should be followed:
* <ul>
* <li>Validate the format of the ID to ensure it adheres to system requirements.</li>
* <li>Handle null or empty values gracefully, providing appropriate error messages
* or default behavior where necessary.</li>
* </ul>
*/
private String userId;
@java.lang.SuppressWarnings("all")
@lombok.Generated
public GetterSetterJavadocLong() {
}
/**
* This field represents the unique identifier for a user in the system. It is used
* throughout the application to uniquely identify and retrieve user-related data.
* The ID is typically generated by the database and is guaranteed to be unique
* within the context of the system.
*
* <p>The ID is an integral part of various operations, including but not limited to:
* <ul>
* <li>Authenticating users during login processes.</li>
* <li>Associating user-specific preferences and settings.</li>
* <li>Tracking user activity and logs for auditing purposes.</li>
* <li>Facilitating relationships between users and other entities such as orders,
* messages, or roles within the system.</li>
* </ul>
*
* <p>Key characteristics of the {@code userId} field:
* <ul>
* <li><strong>Immutability:</strong> Once assigned, the ID must not be modified to
* ensure data integrity.</li>
* <li><strong>Security:</strong> Access to this field should be controlled to prevent
* unauthorized modifications or data leakage.</li>
* <li><strong>Uniqueness:</strong> The ID must be unique within the system. For
* distributed systems, consider using GUIDs or UUIDs to avoid collisions.</li>
* </ul>
*
* <p>Example usage:
* <pre>
* User user = userService.getUserById(userId);
* if (user != null) {
* System.out.println("User found: " + user.getName());
* } else {
* System.out.println("User not found.");
* }
* </pre>
*
* <p>Developers should ensure that the ID complies with constraints imposed by the
* database schema, such as length and format restrictions. Furthermore, it is
* recommended to validate the ID before persisting or using it in critical operations.
*
* <p>For methods or constructors that accept the {@code userId} as a parameter, the
* following guidelines should be followed:
* <ul>
* <li>Validate the format of the ID to ensure it adheres to system requirements.</li>
* <li>Handle null or empty values gracefully, providing appropriate error messages
* or default behavior where necessary.</li>
* </ul>
*/
@java.lang.SuppressWarnings("all")
@lombok.Generated
public String getUserId() {
return this.userId;
}
/**
* This field represents the unique identifier for a user in the system. It is used
* throughout the application to uniquely identify and retrieve user-related data.
* The ID is typically generated by the database and is guaranteed to be unique
* within the context of the system.
*
* <p>The ID is an integral part of various operations, including but not limited to:
* <ul>
* <li>Authenticating users during login processes.</li>
* <li>Associating user-specific preferences and settings.</li>
* <li>Tracking user activity and logs for auditing purposes.</li>
* <li>Facilitating relationships between users and other entities such as orders,
* messages, or roles within the system.</li>
* </ul>
*
* <p>Key characteristics of the {@code userId} field:
* <ul>
* <li><strong>Immutability:</strong> Once assigned, the ID must not be modified to
* ensure data integrity.</li>
* <li><strong>Security:</strong> Access to this field should be controlled to prevent
* unauthorized modifications or data leakage.</li>
* <li><strong>Uniqueness:</strong> The ID must be unique within the system. For
* distributed systems, consider using GUIDs or UUIDs to avoid collisions.</li>
* </ul>
*
* <p>Example usage:
* <pre>
* User user = userService.getUserById(userId);
* if (user != null) {
* System.out.println("User found: " + user.getName());
* } else {
* System.out.println("User not found.");
* }
* </pre>
*
* <p>Developers should ensure that the ID complies with constraints imposed by the
* database schema, such as length and format restrictions. Furthermore, it is
* recommended to validate the ID before persisting or using it in critical operations.
*
* <p>For methods or constructors that accept the {@code userId} as a parameter, the
* following guidelines should be followed:
* <ul>
* <li>Validate the format of the ID to ensure it adheres to system requirements.</li>
* <li>Handle null or empty values gracefully, providing appropriate error messages
* or default behavior where necessary.</li>
* </ul>
*
* @param userId the unique identifier assigned to a user. This value must be non-null
* and conform to the format defined by the system. Passing a null or
* invalid ID may result in an {@link IllegalArgumentException} or
* similar error.
* @param databaseConnection the connection to the database used for retrieving or
* persisting the user ID. This parameter is required for
* database-related operations and must be properly closed
* after use to prevent resource leaks.
* @param userRole the role associated with the user (e.g., "admin", "user", "guest").
* This parameter may influence access control and permissions
* granted to the user within the system.
*/
@java.lang.SuppressWarnings("all")
@lombok.Generated
public void setUserId(final String userId) {
this.userId = userId;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@lombok.Generated
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof GetterSetterJavadocLong)) return false;
final GetterSetterJavadocLong other = (GetterSetterJavadocLong) o;
if (!other.canEqual((java.lang.Object) this)) return false;
final java.lang.Object this$userId = this.getUserId();
final java.lang.Object other$userId = other.getUserId();
if (this$userId == null ? other$userId != null : !this$userId.equals(other$userId)) return false;
return true;
}
@java.lang.SuppressWarnings("all")
@lombok.Generated
protected boolean canEqual(final java.lang.Object other) {
return other instanceof GetterSetterJavadocLong;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@lombok.Generated
public int hashCode() {
final int PRIME = 59;
int result = 1;
final java.lang.Object $userId = this.getUserId();
result = result * PRIME + ($userId == null ? 43 : $userId.hashCode());
return result;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@lombok.Generated
public java.lang.String toString() {
return "GetterSetterJavadocLong(userId=" + this.getUserId() + ")";
}
}
@@ -1,5 +1,6 @@
@java.lang.SuppressWarnings("serial")
class UtilityClassInner {
static final class UtilClass {
static final class UtilClass implements java.io.Serializable {
@java.lang.SuppressWarnings("all")
@lombok.Generated
private UtilClass() {
@@ -0,0 +1,8 @@
// version 14:
import lombok.experimental.Delegate;
record DelegateOnRecord(Runnable runnable) {
/* Implicit */ private final Runnable runnable;
public @java.lang.SuppressWarnings("all") @lombok.Generated void run() {
this.runnable.run();
}
}
@@ -132,3 +132,148 @@ class GetterSetterJavadoc3 {
return this;
}
}
@lombok.Data class GetterSetterJavadocLong {
private String userId;
/**
* This field represents the unique identifier for a user in the system. It is used
* throughout the application to uniquely identify and retrieve user-related data.
* The ID is typically generated by the database and is guaranteed to be unique
* within the context of the system.
*
* <p>The ID is an integral part of various operations, including but not limited to:
* <ul>
* <li>Authenticating users during login processes.</li>
* <li>Associating user-specific preferences and settings.</li>
* <li>Tracking user activity and logs for auditing purposes.</li>
* <li>Facilitating relationships between users and other entities such as orders,
* messages, or roles within the system.</li>
* </ul>
*
* <p>Key characteristics of the {@code userId} field:
* <ul>
* <li><strong>Immutability:</strong> Once assigned, the ID must not be modified to
* ensure data integrity.</li>
* <li><strong>Security:</strong> Access to this field should be controlled to prevent
* unauthorized modifications or data leakage.</li>
* <li><strong>Uniqueness:</strong> The ID must be unique within the system. For
* distributed systems, consider using GUIDs or UUIDs to avoid collisions.</li>
* </ul>
*
* <p>Example usage:
* <pre>
* User user = userService.getUserById(userId);
* if (user != null) {
* System.out.println("User found: " + user.getName());
* } else {
* System.out.println("User not found.");
* }
* </pre>
*
* <p>Developers should ensure that the ID complies with constraints imposed by the
* database schema, such as length and format restrictions. Furthermore, it is
* recommended to validate the ID before persisting or using it in critical operations.
*
* <p>For methods or constructors that accept the {@code userId} as a parameter, the
* following guidelines should be followed:
* <ul>
* <li>Validate the format of the ID to ensure it adheres to system requirements.</li>
* <li>Handle null or empty values gracefully, providing appropriate error messages
* or default behavior where necessary.</li>
* </ul>
*/
public @java.lang.SuppressWarnings("all") @lombok.Generated String getUserId() {
return this.userId;
}
/**
* This field represents the unique identifier for a user in the system. It is used
* throughout the application to uniquely identify and retrieve user-related data.
* The ID is typically generated by the database and is guaranteed to be unique
* within the context of the system.
*
* <p>The ID is an integral part of various operations, including but not limited to:
* <ul>
* <li>Authenticating users during login processes.</li>
* <li>Associating user-specific preferences and settings.</li>
* <li>Tracking user activity and logs for auditing purposes.</li>
* <li>Facilitating relationships between users and other entities such as orders,
* messages, or roles within the system.</li>
* </ul>
*
* <p>Key characteristics of the {@code userId} field:
* <ul>
* <li><strong>Immutability:</strong> Once assigned, the ID must not be modified to
* ensure data integrity.</li>
* <li><strong>Security:</strong> Access to this field should be controlled to prevent
* unauthorized modifications or data leakage.</li>
* <li><strong>Uniqueness:</strong> The ID must be unique within the system. For
* distributed systems, consider using GUIDs or UUIDs to avoid collisions.</li>
* </ul>
*
* <p>Example usage:
* <pre>
* User user = userService.getUserById(userId);
* if (user != null) {
* System.out.println("User found: " + user.getName());
* } else {
* System.out.println("User not found.");
* }
* </pre>
*
* <p>Developers should ensure that the ID complies with constraints imposed by the
* database schema, such as length and format restrictions. Furthermore, it is
* recommended to validate the ID before persisting or using it in critical operations.
*
* <p>For methods or constructors that accept the {@code userId} as a parameter, the
* following guidelines should be followed:
* <ul>
* <li>Validate the format of the ID to ensure it adheres to system requirements.</li>
* <li>Handle null or empty values gracefully, providing appropriate error messages
* or default behavior where necessary.</li>
* </ul>
*
* @param userId the unique identifier assigned to a user. This value must be non-null
* and conform to the format defined by the system. Passing a null or
* invalid ID may result in an {@link IllegalArgumentException} or
* similar error.
* @param databaseConnection the connection to the database used for retrieving or
* persisting the user ID. This parameter is required for
* database-related operations and must be properly closed
* after use to prevent resource leaks.
* @param userRole the role associated with the user (e.g., "admin", "user", "guest").
* This parameter may influence access control and permissions
* granted to the user within the system.
*/
public @java.lang.SuppressWarnings("all") @lombok.Generated void setUserId(final String userId) {
this.userId = userId;
}
public @java.lang.Override @java.lang.SuppressWarnings("all") @lombok.Generated boolean equals(final java.lang.Object o) {
if ((o == this))
return true;
if ((! (o instanceof GetterSetterJavadocLong)))
return false;
final GetterSetterJavadocLong other = (GetterSetterJavadocLong) o;
if ((! other.canEqual((java.lang.Object) this)))
return false;
final java.lang.Object this$userId = this.getUserId();
final java.lang.Object other$userId = other.getUserId();
if (((this$userId == null) ? (other$userId != null) : (! this$userId.equals(other$userId))))
return false;
return true;
}
protected @java.lang.SuppressWarnings("all") @lombok.Generated boolean canEqual(final java.lang.Object other) {
return (other instanceof GetterSetterJavadocLong);
}
public @java.lang.Override @java.lang.SuppressWarnings("all") @lombok.Generated int hashCode() {
final int PRIME = 59;
int result = 1;
final java.lang.Object $userId = this.getUserId();
result = ((result * PRIME) + (($userId == null) ? 43 : $userId.hashCode()));
return result;
}
public @java.lang.Override @java.lang.SuppressWarnings("all") @lombok.Generated java.lang.String toString() {
return (("GetterSetterJavadocLong(userId=" + this.getUserId()) + ")");
}
public @java.lang.SuppressWarnings("all") @lombok.Generated GetterSetterJavadocLong() {
super();
}
}
@@ -1,5 +1,5 @@
class UtilityClassInner {
static final @lombok.experimental.UtilityClass class UtilClass {
@java.lang.SuppressWarnings("serial") class UtilityClassInner {
static final @lombok.experimental.UtilityClass class UtilClass implements java.io.Serializable {
private @java.lang.SuppressWarnings("all") @lombok.Generated UtilClass() {
super();
throw new java.lang.UnsupportedOperationException("This is a utility class and cannot be instantiated");
@@ -0,0 +1,6 @@
//platform !eclipse: Requires a 'full' eclipse with intialized workspace, and we don't (yet) have that set up properly in the test run.
//version 14:
import lombok.experimental.Delegate;
record DelegateOnRecord(@Delegate Runnable runnable) {
}
@@ -62,3 +62,67 @@ class GetterSetterJavadoc5 {
*/
@lombok.Getter @lombok.Setter private int fieldName;
}
@lombok.Data
class GetterSetterJavadocLong {
/**
* This field represents the unique identifier for a user in the system. It is used
* throughout the application to uniquely identify and retrieve user-related data.
* The ID is typically generated by the database and is guaranteed to be unique
* within the context of the system.
*
* <p>The ID is an integral part of various operations, including but not limited to:
* <ul>
* <li>Authenticating users during login processes.</li>
* <li>Associating user-specific preferences and settings.</li>
* <li>Tracking user activity and logs for auditing purposes.</li>
* <li>Facilitating relationships between users and other entities such as orders,
* messages, or roles within the system.</li>
* </ul>
*
* <p>Key characteristics of the {@code userId} field:
* <ul>
* <li><strong>Immutability:</strong> Once assigned, the ID must not be modified to
* ensure data integrity.</li>
* <li><strong>Security:</strong> Access to this field should be controlled to prevent
* unauthorized modifications or data leakage.</li>
* <li><strong>Uniqueness:</strong> The ID must be unique within the system. For
* distributed systems, consider using GUIDs or UUIDs to avoid collisions.</li>
* </ul>
*
* <p>Example usage:
* <pre>
* User user = userService.getUserById(userId);
* if (user != null) {
* System.out.println("User found: " + user.getName());
* } else {
* System.out.println("User not found.");
* }
* </pre>
*
* <p>Developers should ensure that the ID complies with constraints imposed by the
* database schema, such as length and format restrictions. Furthermore, it is
* recommended to validate the ID before persisting or using it in critical operations.
*
* <p>For methods or constructors that accept the {@code userId} as a parameter, the
* following guidelines should be followed:
* <ul>
* <li>Validate the format of the ID to ensure it adheres to system requirements.</li>
* <li>Handle null or empty values gracefully, providing appropriate error messages
* or default behavior where necessary.</li>
* </ul>
*
* @param userId the unique identifier assigned to a user. This value must be non-null
* and conform to the format defined by the system. Passing a null or
* invalid ID may result in an {@link IllegalArgumentException} or
* similar error.
* @param databaseConnection the connection to the database used for retrieving or
* persisting the user ID. This parameter is required for
* database-related operations and must be properly closed
* after use to prevent resource leaks.
* @param userRole the role associated with the user (e.g., "admin", "user", "guest").
* This parameter may influence access control and permissions
* granted to the user within the system.
*/
private String userId;
}
@@ -1,4 +1,5 @@
@java.lang.SuppressWarnings("serial")
class UtilityClassInner {
@lombok.experimental.UtilityClass
class UtilClass {}
class UtilClass implements java.io.Serializable {}
}
+27 -1
View File
@@ -10,7 +10,13 @@
</div><div class="row text-center">
<h2><a href="/lombok-edge.jar" id="downloadLink">Download edge release now!</a></h2>
<p>
You can use the edge release from maven using the projectlombok.org repository:<pre>
You can use the edge release from maven using the projectlombok.org repository.
This requires:<ul>
<li>Adding the lombok maven repository to your <code>repositories</code> section</li>
<li>Adding lombok as a dependency to your project in the <code>dependencies</code> section, specifying version <code>edge-SNAPSHOT</code>.</li>
<li>Adding lombok as an annotation processor in the <code>annotationProcessorPaths</code> section, specifying version <code>edge-SNAPSHOT</code>.</li>
</ul>
These sections in your pom file should look like this:<pre>
&lt;repositories&gt;
&lt;repository&gt;
&lt;id&gt;projectlombok.org&lt;/id&gt;
@@ -26,6 +32,26 @@
&lt;scope&gt;provided&lt;/scope&gt;
&lt;/dependency&gt;
&lt;/dependencies&gt;</pre>
<pre>
&lt;build&gt;
&lt;plugins&gt;
&lt;plugin&gt;
&lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
&lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
&lt;configuration&gt;
&lt;annotationProcessorPaths&gt;
&lt;path&gt;
&lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
&lt;artifactId&gt;lombok&lt;/artifactId&gt;
&lt;version&gt;edge-SNAPSHOT&lt;/version&gt;
&lt;/path&gt;
&lt;/annotationProcessorPaths&gt;
&lt;/configuration&gt;
&lt;/plugin&gt;
&lt;/plugins&gt;
&lt;/build&gt;
</pre>
</p>
<p>
You can use the edge release from gradle using the projectlombok.org repository:<pre>
+2 -2
View File
@@ -66,7 +66,7 @@
</p><p>
Now that the "method" mode is clear, putting a <code>@Builder</code> annotation on a constructor functions similarly; effectively, constructors are just static methods that have a special syntax to invoke them: Their 'return type' is the class they construct, and their type parameters are the same as the type parameters of the class itself.
</p><p>
Finally, applying <code>@Builder</code> to a class is as if you added <code>@AllArgsConstructor(access = AccessLevel.PACKAGE)</code> to the class and applied the <code>@Builder</code> annotation to this all-args-constructor. This only works if you haven't written any explicit constructors yourself or allowed lombok to create one such as with <code>@NoArgsConstructor</code>. If you do have an explicit constructor, put the <code>@Builder</code> annotation on the constructor instead of on the class. Note that if you put both `@Value` and `@Builder` on a class, the package-private constructor that `@Builder` wants to generate 'wins' and suppresses the constructor that `@Value` wants to make.
Finally, applying <code>@Builder</code> to a class is as if you added <code>@AllArgsConstructor(access = AccessLevel.PACKAGE)</code> to the class and applied the <code>@Builder</code> annotation to this all-args-constructor. This only works if you haven't written any explicit constructors yourself or allowed lombok to create one such as with <code>@NoArgsConstructor</code>. If you do have an explicit constructor, put the <code>@Builder</code> annotation on the constructor instead of on the class. Note that if you put both <code>@Value</code> and <code>@Builder</code> on a class, the package-private constructor that <code>@Builder</code> wants to generate 'wins' and suppresses the constructor that <code>@Value</code> wants to make.
</p><p>
If using <code>@Builder</code> to generate builders to produce instances of your own class (this is always the case unless adding <code>@Builder</code> to a method that doesn't return your own type), you can use <code>@Builder(toBuilder = true)</code> to also generate an instance method in your class called <code>toBuilder()</code>; it creates a new builder that starts out with all the values of this instance. You can put the <code>@Builder.ObtainVia</code> annotation on the parameters (in case of a constructor or method) or fields (in case of <code>@Builder</code> on a type) to indicate alternative means by which the value for that field/parameter is obtained from this instance. For example, you can specify a method to be invoked: <code>@Builder.ObtainVia(method = "calculateFoo")</code>.
</p><p>
@@ -228,7 +228,7 @@ public class JacksonExample {
You can use <code>@Builder</code> for copy constructors: <code>foo.toBuilder().build()</code> makes a shallow clone. Consider suppressing the generating of the
<code>builder</code> method if you just want this functionality, by using: <code>@Builder(toBuilder = true, builderMethodName = "")</code>.
</p><p>
Due to a peculiar way javac processes static imports, trying to do a non-star static import of the static <code>builder()</code> method won't work. Either use a star static import: `import static TypeThatHasABuilder.*;` or don't statically import the <code>builder</code> method.
Due to a peculiar way javac processes static imports, trying to do a non-star static import of the static <code>builder()</code> method won't work. Either use a star static import: <code>import static TypeThatHasABuilder.*;</code> or don't statically import the <code>builder</code> method.
</p><p>
If setting the access level to <code>PROTECTED</code>, all methods generated inside the builder class are actually generated as <code>public</code>; the meaning of the
<code>protected</code> keyword is different inside the inner class, and the precise behavior that <code>PROTECTED</code> would indicate (access by any source in the same package is allowed, as well as any subclasses <em>from the outer class, marked with <code>@Builder</code></em> is not possible, and marking the inner members <code>public</code> is as close as we can get.
+1 -1
View File
@@ -3,7 +3,7 @@
<@f.scaffold title="@Locked" logline="Pop it and <strong>lock</strong> it! <code>ReentrantLock</code>, now with less hassle.">
<@f.history>
<p>
<code>@Locked</code> was introduced in lombok v1.20.
<code>@Locked</code> was introduced in lombok v1.18.32.
</p>
</@f.history>
+1 -1
View File
@@ -27,7 +27,7 @@
<@f.snippets name="With" />
<@f.confKeys>
<><dt>
<dt>
<code>lombok.accessors.prefix</code> += <em>a field prefix</em> (default: empty list)
</dt><dd>
This is a list property; entries can be added with the <code>+=</code> operator. Inherited prefixes from parent config files can be removed with the <code>-=</code> operator. Lombok will strip any matching field prefix from the name of a field in order to determine the name of the getter/setter to generate. For example, if <code>m</code> is one of the prefixes listed in this setting, then a field named <code>mFoobar</code> will result in a getter named <code>getFoobar()</code>, not <code>getMFoobar()</code>. An explicitly configured <code>prefix</code> parameter of an <a href="/features/experimental/Accessors"><code>@Accessors</code></a> annotation takes precedence over this setting.
@@ -87,7 +87,7 @@
<ol class="snippet example oneliner">
<li><code>lombok.addNullAnnotations = <em>&lt;flavor&gt;</em></code></li>
</ol>
Many <em>flavors</em> are available: <code>javax</code> (=JSR305; not recommended), <code>jakarta</code>, <code>eclipse</code>, <code>jetbrains</code>, <code>netbeans</code>, <code>androidx</code>, <code>android.support</code> (deprecated within android), <code>checkerframework</code> (recommended), <code>findbugs</code>, <code>spring</code>, <code>jml</code>, or define your own via <code>CUSTOM:fully.qualified.NonNullAnnotation:fully.qualified.NullableAnnotation</code>; if your nullity annotation is solely of the type use style (it annotates types, such as eclipse's and checkerframework's offerings, versus annotating methods and parameters), the format is <code>CUSTOM:TYPE_USE:nonnullanno:nullableanno</code>.<br />
Many <em>flavors</em> are available: <code>jspecify</code> (recommended), <code>checkerframework</code> (recommended), <code>jakarta</code>, <code>eclipse</code>, <code>jetbrains</code>, <code>netbeans</code>, <code>androidx</code>, <code>findbugs</code>, <code>spring</code>, <code>jml</code>, <code>javax</code> (=JSR305; not recommended), <code>android.support</code> (deprecated within android), or define your own via <code>CUSTOM:fully.qualified.NonNullAnnotation:fully.qualified.NullableAnnotation</code>; if your nullity annotation is solely of the type use style (it annotates types, such as eclipse's and checkerframework's offerings, versus annotating methods and parameters), the format is <code>CUSTOM:TYPE_USE:nonnullanno:nullableanno</code>.<br />
<em>This feature was added in lombok v1.18.12</em>.<br />
</p><p>
Lombok can be configured to add <code>@lombok.Generated</code> annotations to all generated nodes where possible; useful for JaCoCo (which has built in support),
@@ -11,8 +11,6 @@
<ul>
<li>
Ugly syntax. The syntax of this feature is not optimal, but it is the least convoluted syntax that could possibly work (for now!)
</li><li>
Possibly java 9 will offer (much) better ways of supporting this feature.
</li><li>
Uncertainty: Future versions of javac may break this feature, and we may not be able to restore it.
</li>
+5 -5
View File
@@ -17,17 +17,17 @@
<@s.section title="Gradle without a plugin">
<p>
If you don't want to use the plugin, gradle has the built-in <code>compileOnly</code> scope, which can be used to tell gradle to add lombok only during compilation. Your <code>build.gradle</code> will look like:<pre>
If you don't want to use the plugin, gradle has the built-in <code>compileOnly</code> scope, which can be used to tell gradle to add lombok only during compilation. Your <code>build.gradle</code> or <code>build.gradle.kts</code> will look like:<pre>
repositories {
mavenCentral()
}
dependencies {
compileOnly 'org.projectlombok:lombok:${version}'
annotationProcessor 'org.projectlombok:lombok:${version}'
compileOnly("org.projectlombok:lombok:${version}")
annotationProcessor("org.projectlombok:lombok:${version}")
testCompileOnly 'org.projectlombok:lombok:${version}'
testAnnotationProcessor 'org.projectlombok:lombok:${version}'
testCompileOnly("org.projectlombok:lombok:${version}")
testAnnotationProcessor("org.projectlombok:lombok:${version}")
}</pre>
</p><p>
Remember that you still have to download <code>lombok.jar</code> (or find it in gradle's caches) and run it as a jarfile, if you wish to program in eclipse. The plugin makes that part easier.
+18 -13
View File
@@ -22,20 +22,25 @@
&lt;/dependencies&gt;
</pre>
</p>
</@s.section>
<@s.section title="JDK9+ with module-info.java">
<p>
The configuration of the compiler plug-in should contain the following:<pre>
&lt;annotationProcessorPaths&gt;
&lt;path&gt;
&lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
&lt;artifactId&gt;lombok&lt;/artifactId&gt;
&lt;version&gt;${version}&lt;/version&gt;
&lt;/path&gt;
&lt;/annotationProcessorPaths&gt;
</pre>
</p>
You also need to add lombok as an annotation processor. This is mandatory starting with JDK23, or JDK9+ if compiling as modules (you have <code>module-info.java</code> files in your build):<pre>
&lt;build&gt;
&lt;plugins&gt;
&lt;plugin&gt;
&lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
&lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
&lt;configuration&gt;
&lt;annotationProcessorPaths&gt;
&lt;path&gt;
&lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
&lt;artifactId&gt;lombok&lt;/artifactId&gt;
&lt;version&gt;${version}&lt;/version&gt;
&lt;/path&gt;
&lt;/annotationProcessorPaths&gt;
&lt;/configuration&gt;
&lt;/plugin&gt;
&lt;/plugins&gt;
&lt;/build&gt;
</@s.section>
<@s.section title="Eclipse Compiler (ECJ/JDT)">
@@ -7,11 +7,9 @@ import javax.persistence.Id;
import javax.persistence.Column;
import javax.validation.constraints.Max;
@AllArgsConstructor(onConstructor=@__(@Inject))
@AllArgsConstructor(onConstructor_=@Inject)
public class OnXExample {
// @Getter(onMethod=@__({@Id, @Column(name="unique-id")})) //JDK7
// @Setter(onParam=@__(@Max(10000))) //JDK7
@Getter(onMethod_={@Id, @Column(name="unique-id")}) //JDK8
@Setter(onParam_=@Max(10000)) //JDK8
@Getter(onMethod_={@Id, @Column(name="unique-id")})
@Setter(onParam_=@Max(10000))
private long unid;
}