Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/workflows/check-since-tags.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Check @since tags

# Fails the build if any Java source under CodenameOne/src carries an @since
# javadoc tag whose version does not correspond to an existing git tag in
# this repository. Without this gate, prose can advertise APIs as available
# in versions that never shipped (e.g. "@since 9.0").

permissions:
contents: read

on:
workflow_dispatch:
pull_request:
branches:
- master
paths:
- 'CodenameOne/src/**/*.java'
- 'scripts/check-since-tags.sh'
- '.github/workflows/check-since-tags.yml'
push:
branches:
- master
paths:
- 'CodenameOne/src/**/*.java'
- 'scripts/check-since-tags.sh'
- '.github/workflows/check-since-tags.yml'

jobs:
check-since-tags:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# Full history including all tags so `git tag --list` returns
# the complete set of released versions.
fetch-depth: 0
fetch-tags: true

- name: Validate @since references against git tags
shell: bash
run: scripts/check-since-tags.sh
60 changes: 60 additions & 0 deletions .github/workflows/errorprone.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Error Prone checks

# Runs the framework's custom Error Prone BugCheckers (currently just
# BanClassForName) over CodenameOne/src. The check fails the build when
# someone adds a Class.forName(...) call, which silently breaks on
# ParparVM (iOS) because the iOS port cannot resolve classes by string
# name at runtime.

permissions:
contents: read

on:
workflow_dispatch:
pull_request:
branches:
- master
paths:
- 'CodenameOne/src/**/*.java'
- 'maven/errorprone-checks/**'
- 'maven/core/pom.xml'
- 'maven/pom.xml'
- '.github/workflows/errorprone.yml'
push:
branches:
- master
paths:
- 'CodenameOne/src/**/*.java'
- 'maven/errorprone-checks/**'
- 'maven/core/pom.xml'
- 'maven/pom.xml'
- '.github/workflows/errorprone.yml'

jobs:
errorprone:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
# Error Prone requires JDK 11+; we pick 17 to match the
# framework's Android-port JAVA17_HOME requirement.
distribution: temurin
java-version: 17
cache: maven

- name: Install errorprone-checks
working-directory: maven
# The checker module must be installed to the local repo BEFORE
# core compiles. We can't rely on the reactor ordering: core
# references errorprone-checks only via annotationProcessorPaths,
# which Maven does not treat as a build-time dependency, so the
# reactor would otherwise schedule core first and fail to resolve
# com.codenameone:errorprone-checks:8.0-SNAPSHOT.
run: mvn -B -Perrorprone -pl errorprone-checks -am install -DskipTests

- name: Run Error Prone over the core module
working-directory: maven
run: mvn -B -Perrorprone -pl core -am install -DskipTests
3 changes: 3 additions & 0 deletions CodenameOne/src/com/codename1/location/GeofenceManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,9 @@ public boolean isBubble(String id) {
}

/// Gets the currently registered Listener class.
// The listener class name is persisted to Storage during registration; we
// have no Class literal here, so reflective resolution is unavoidable.
@SuppressWarnings("BanClassForName")
public synchronized Class<? extends GeofenceListener> getListenerClass() {
if (listenerClass == null) {
String className = (String) Storage.getInstance().readObject(LISTENER_CLASS_KEY);
Expand Down
4 changes: 4 additions & 0 deletions CodenameOne/src/com/codename1/system/NativeLookup.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ public static void setVerbose(boolean aVerbose) {
///
/// @return an instance of that interface that can be invoked or null if the native interface isn't
/// present on the underlying platform (e.g. simulator platform).
// NativeLookup is itself the sanctioned escape hatch for class-by-name
// resolution; the JavaSE simulator path falls back to a name-derived
// *Impl lookup that the registered map cannot cover.
@SuppressWarnings("BanClassForName")
public static <T extends NativeInterface> T create(Class<T> c) {
try {
Class cls = interfaceToClassLookup.get(c);
Expand Down
4 changes: 4 additions & 0 deletions CodenameOne/src/com/codename1/testing/DeviceRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ public void runTests() {
/// #### Parameters
///
/// - `testClassName`: the class name of the test case
// The test runner receives the unit test class as a String (it is the
// entry point invoked from the device-side test bootstrap), so loading
// it by name is the whole point of the method.
@SuppressWarnings("BanClassForName")
public void runTest(String testClassName) {
try {
final UnitTest t = (UnitTest) Class.forName(testClassName).newInstance();
Expand Down
6 changes: 4 additions & 2 deletions docs/developer-guide/.gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
book-cover.generated.svg
book-cover.generated.png
# Vale syncs upstream style packages here, but the project-specific vocabulary
# (config/vocabularies/CodenameOne) is tracked so CI runs see the same word
# list local contributors do.
# (config/vocabularies/CodenameOne) and our locally authored rule directory
# (styles/CodenameOneRules) are tracked so CI runs see the same word list
# and custom checks local contributors do.
styles/*
!styles/config/
!styles/CodenameOneRules/
styles/config/*
!styles/config/vocabularies/
styles/config/vocabularies/*
Expand Down
2 changes: 1 addition & 1 deletion docs/developer-guide/.vale.ini
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ Packages = https://github.com/errata-ai/packages/releases/download/v0.2.0/Micros
# removes the conjunction the reader relies on.

[*.{adoc,asciidoc}]
BasedOnStyles = Microsoft, proselint, write-good
BasedOnStyles = Microsoft, proselint, write-good, CodenameOneRules
TokenIgnores = (?s)// vale-skip:[^\n]*\n[^\n]+\n

write-good.Passive = NO
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2565,7 +2565,7 @@ image::img/components-imageviewer-multi.png[An ImageViewer with many elements is

Notice that you use a https://www.codenameone.com/javadoc/com/codename1/ui/list/ListModel.html[ListModel] to allow swiping between images.

From Codename One 9.0, `ImageViewer` also supports optional side arrows (material font icons) and an optional thumbnail strip for direct image navigation:
`ImageViewer` also supports optional side arrows (material font icons) and an optional thumbnail strip for direct image navigation:

[source,java]
----
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
extends: existence
message: "'%s' refers to a Codename One version that has not been released. The current release line is 7.0.x; do not write 'Codename One 8', 'Codename One 9', or 'Codename One 7.1'."
level: error
ignorecase: false
nonword: true
# `vocab: false` is critical: by default Vale subtracts any term from
# `styles/config/vocabularies/CodenameOne/accept.txt` (which includes
# "Codename") from matches, which would silently swallow every hit because
# our patterns start with "Codename One".
vocab: false
# Match the version number in isolation, then assert "Codename One" precedes it
# in raw text (vale RE2 has no lookbehind, so we use \b on either side and rely
# on the regex matching unique enough strings inside prose).
#
# Block:
# - "Codename One 8"/"Codename One 9"/... (no major version >= 8 has shipped)
# - "Codename One 7.1"/"Codename One 7.2"/... (latest 7.x is 7.0.81; nothing
# past 7.0 has shipped)
# We deliberately allow plain "Codename One 7" and "Codename One 7.0.x"
# because those are the live release line.
tokens:
- '\bCodename One ([89]|[1-9][0-9]+)\b'
- '\bCodename One 7\.[1-9][0-9]*\b'
75 changes: 75 additions & 0 deletions maven/core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,81 @@
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</profile>
<!--
Opt-in Error Prone pass over CodenameOne/src. Run via
`mvn -Perrorprone install` on JDK 11+. Currently enforces
BanClassForName (see maven/errorprone-checks). Kept opt-in
because the framework's primary build runs on JDK 8 where
Error Prone cannot load.
-->
<profile>
<id>errorprone</id>
<properties>
<errorprone.version>2.27.1</errorprone.version>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<showWarnings>true</showWarnings>
<!--
Fork the compiler so the -J flags below
reach a fresh javac JVM. Without forking,
javac runs in the Maven process and the
module exports never apply, leaving
Error Prone's BaseErrorProneJavaCompiler
unable to access jdk.compiler internals.
-->
<fork>true</fork>
<compilerArgs combine.children="append">
<arg>-XDcompilePolicy=simple</arg>
<!--
-XepDisableAllChecks turns off Error
Prone's built-in rules so only the
checks we explicitly enable run. The
framework targets Java 1.5/1.8 idioms
and many built-in checks would fire on
legacy code we have no intention of
rewriting today.
-->
<arg>-Xplugin:ErrorProne -XepDisableAllChecks -Xep:BanClassForName:ERROR</arg>
<!-- JDK 16+ closes javac internals; Error
Prone needs these to introspect the
AST. The -J prefix routes each flag to
the forked javac JVM. -->
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED</arg>
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
<version>${errorprone.version}</version>
</path>
<path>
<groupId>com.codenameone</groupId>
<artifactId>errorprone-checks</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>


Expand Down
89 changes: 89 additions & 0 deletions maven/errorprone-checks/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.codenameone</groupId>
<artifactId>codenameone</artifactId>
<version>8.0-SNAPSHOT</version>
</parent>

<artifactId>errorprone-checks</artifactId>
<packaging>jar</packaging>
<name>codenameone-errorprone-checks</name>
<description>
Custom Error Prone bug checkers that the framework build runs over
CodenameOne/src. Currently enforces:
- BanClassForName: refuses any use of java.lang.Class.forName(...)
Built only on JDK 11+ (the minimum Error Prone supports); the
framework's primary JDK 8 build path skips this module via the
profile activation below.
</description>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<errorprone.version>2.27.1</errorprone.version>
</properties>

<dependencies>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_check_api</artifactId>
<version>${errorprone.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
<version>${errorprone.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service-annotations</artifactId>
<version>1.1.1</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<!--
Error Prone's BugChecker classes reference internal
javac symbols (com.sun.tools.javac.*) that the
module system hides starting with JDK 16. Exporting
them at compile time lets our checker compile;
they're re-exported at runtime by the core build
configuration that invokes Error Prone.
-->
<compilerArgs>
<arg>--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</arg>
<arg>--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
<arg>--add-exports=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED</arg>
<arg>--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</arg>
<arg>--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED</arg>
<arg>--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED</arg>
<arg>--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>
<arg>--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg>
<arg>--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service</artifactId>
<version>1.1.1</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
Loading
Loading