Skip to content

Releases: juangp3/j2cpp

J2C Modern Edition 0.6.1 (preview)

Pre-release

Choose a tag to compare

@github-actions github-actions released this 27 Oct 18:58

Building

  • Translating again into the same output directory keeps the build's
    objects and libraries, and the files that come out the same keep their
    modification time, so make, j2c build, j2c run and j2c test
    compile only what changed. A second j2c run against the bundled runtime
    compiled all of its 538 files again; it now compiles none. Changing the
    compiler or its flags (CXX, CFLAGS) compiles everything again, and
    every object now depends on the headers it includes (the stubs, natives
    and dependencies did not).

Translation

  • An enhanced for over an array converts each element to the loop
    variable's type. for (long v : int[]) kept v an int, so shifts and
    overflow silently gave wrong results; unboxing (double v : Double[]) and
    boxing (Integer v : int[]) did not compile.
  • An abstract class that inherits the same abstract method from its
    superclass and from an interface can call it; the call was ambiguous in
    C++.
  • Translating with --runtime and a dependency on the class path no longer
    prints JDT's internal Status ERROR: ... Could not retrieve declared methods lines, which looked like a failure. The output did not change;
    one note on stderr now says that JDT logged an internal error.

Extension and agents

  • The VS Code extension and the Claude Code plugin have an icon.
  • The hint for J2C-LAMBDA-INTERSECTION-TYPE-VARIABLE names the safe
    rewrite: a generic interface that extends every type of the intersection.
    It suggested casting to one functional interface, which drops
    Serializable and changes behavior; the agent benchmark caught an agent
    following it. The benchmark's scoreboard is in docs/AGENT_BENCHMARK.md.

Requirements

  • Java 11 or newer to run the CLI and the VS Code extension.
  • A C++20 compiler for generated Makefiles and C++ output.
  • VS Code 1.85 or newer for the extension.

Assets

  • j2c-cli-0.6.1.jar: standalone CLI (java -jar j2c-cli-0.6.1.jar --help).
  • j2c-0.6.1.vsix: VS Code extension with the same CLI bundled
    (code --install-extension j2c-0.6.1.vsix).
  • juangp3-j2c-mcp-0.6.1.tgz: the npm package of the MCP server
    (npx @juangp3/j2c-mcp), with the same CLI.
  • SHA256SUMS: verify downloads with sha256sum -c SHA256SUMS.

Third-party license notices are in THIRD-PARTY-NOTICES.txt and
licenses/ in the source tree, inside the CLI JAR under
META-INF/j2c-licenses/, and at the root of the VSIX.

J2C Modern Edition 0.6.0 (preview)

Pre-release

Choose a tag to compare

@github-actions github-actions released this 26 Oct 19:43

First release of J2C Modern Edition: a standalone Java-to-C++ CLI and a VS
Code extension that bundles it, parsing Java 17 source and generating
C++20-targeted output.

Command line and extension

  • Standalone CLI with --sourcepath, --classpath, --name,
    --sealed-types advisory|reject, --encoding, --check, and --version.
  • --check lists every compile error and unsupported construct as
    file:line: message, with a summary per kind, without writing output.
  • Translation problems are reported as file:line diagnostics without a stack
    trace. Exit status is 0 on success, 1 for translation problems, and 2 for
    invalid arguments.
  • Source directories skip module-info.java and package-info.java, which
    declare no types; a module declaration no longer fails the check.
  • Sources are read as UTF-8 by default and generated C++ is always UTF-8,
    independent of the platform charset.
  • VS Code: J2C: Translate to C++ and J2C: Check Translatability in the
    editor and Explorer menus. Problems appear in the Problems panel; runs can
    be cancelled, and only one runs at a time.
  • Problems have stable IDs with fix hints (j2c explain), and --format json
    prints machine-readable results with line and column. j2c capabilities
    describes supported features and limitations.
  • Translation refuses to replace a non-empty output directory that J2C did
    not create (its contents would be moved to a backup) unless --force is
    given; the extension asks first.
  • Translation checks every selected file before writing anything, and
    reports the problems of all of them at once. A translation that fails
    this way leaves the output directory as it was: earlier output is not
    moved to the backup, and an empty directory gets no .j2c-output marker.
  • A Java file that is only a dependency (on the source path, not selected)
    and does not compile no longer fails the translation: like a library
    class, it gets a header and stubs from what the compiler resolved, and no
    implementation. The warning J2C-DEPENDENCY-ERRORS, at its first error,
    is printed to stderr and listed in warnings in JSON. Selected files with
    errors still fail.

Runtime (preview)

  • --runtime <directory> translates against a J2C runtime instead of the
    running JDK: its Java sources replace java.*, its C++ natives replace
    the generated stubs, and the Makefile builds its hooks.

  • The repository's runtime/ is written from the Java SE specification and
    covers:

    • String, StringBuilder, the boxed types, Math and Objects;
    • the exception classes, with Java's uncaught-exception printout and exit
      status;
    • the collections: ArrayList, LinkedList, ArrayDeque,
      PriorityQueue, HashMap, LinkedHashMap, TreeMap, their sets,
      Collections, Arrays, Comparator and java.util.function;
    • streams: Stream, IntStream, LongStream, DoubleStream and
      Collectors, sequential and lazy in the JVM's order, with Optional
      and its primitive forms and the summary statistics;
    • String.format, formatted, printf and Formatter, with Java's
      rounding and exception messages (no %t date conversions);
    • java.util.regex (Pattern, Matcher, MatchResult,
      PatternSyntaxException with the JDK's messages), a backtracking
      matcher whose stack lives on the heap, used by String.matches,
      split, replaceAll and replaceFirst: classes with intersection,
      groups (named, atomic), backreferences, look-around, greedy, reluctant
      and possessive quantifiers, and the inline flags.
    • text input and files: System.in, the java.io streams, readers and
      writers (BufferedReader, PrintWriter, FileWriter and the rest),
      File, Scanner (whitespace or literal delimiters, no regular
      expressions), java.nio.file.Files and Path, and the UTF-8,
      ISO-8859-1 and US-ASCII charsets, with the JVM's buffering, malformed
      input handling and exception messages.
    • threads: Thread (start, join, sleep, interrupt, names, daemons, the
      uncaught-exception handlers and printout), ThreadLocal,
      Object.wait, notify and notifyAll, and java.util.concurrent's
      atomics, Executors.newFixedThreadPool with Future,
      CountDownLatch, ReentrantLock with Condition, TimeUnit and
      ConcurrentHashMap, plus Collections.synchronizedList and
      synchronizedMap. Program exit waits for the non-daemon threads.
      System.out and the other shared pieces (string interning, class
      initialization, Math.random) are thread-safe.

    HashMap and HashSet iterate in the JVM's order, so printed maps match.

  • --runtime bundled uses the runtime packaged in the CLI JAR, so no
    repository checkout is needed (the JAR grows by about 250 KB). It is
    extracted on first use into ~/.j2c/cache (or J2C_CACHE_DIR) as
    runtime-<version>-<hash>, reused while its files are intact and
    replaced when one is missing, changed or added; concurrent processes are
    safe. The output equals --runtime with the checkout's runtime/.
    --runtime <directory> is unchanged, and the CLI still translates
    without a runtime by default. See docs/RUNTIME.md.

  • The MCP tools j2c_check, j2c_translate, j2c_fix, j2c_report,
    j2c_build and j2c_test take runtime ("bundled" or a directory),
    and j2c build and j2c test take --runtime bundled.

  • VS Code: the j2c.runtime setting, bundled by default, so Check and
    Translate use the J2C runtime and translated programs run. This changes
    the extension's output: java.* comes from the runtime, so code using JDK
    classes it does not provide (such as java.time) now gets
    J2C-COMPILE-ERROR problems instead of stubs. Set j2c.runtime to
    none for the previous behavior, or to a runtime directory.

  • The order of includes in generated files no longer depends on the
    directory the sources are in (JDT puts it into the keys of generic source
    types), so a runtime gives the same output wherever it is.

  • j2c report names the runtime it compares with as --runtime bundled
    when no runtime directory is given.

  • make J2C_GC=boehm links a program with the Boehm garbage collector,
    which then serves every allocation (Java objects and the runtime's C++
    containers), so memory is reclaimed. Exceptions in flight stay reachable
    while finally blocks run. Threads are registered with the collector;
    make test binaries are not covered.

  • CI translates each program in test/runtime, builds it under
    UndefinedBehaviorSanitizer, and compares its output and exit status with
    java, then does the same with J2C_GC=boehm, collecting every 1000
    allocations. test/runtime/allocation allocates about 1 GB and must stay
    under 100 MB of resident memory with the collector. A program's
    input.txt is its standard input, and each run starts in an empty
    working directory, so programs can write files.

  • synchronized methods now hold the monitor of this, or of the class
    when static; before, the modifier was dropped silently. A synchronized
    block on null throws NullPointerException, and static initializers run
    once when several threads reach a class at the same time. Generated
    Makefiles build with -pthread.

  • Every translation now includes java.lang.Class and
    java.lang.ArrayStoreException, which generated code always uses, and
    programs link the program library again after the -ext library.

  • A lambda or method reference whose types include an inner class of a
    parameterized class (Outer<A>.Inner) translates; it was a compile error
    because the inner class was written raw.

  • A member class of a local or anonymous class that reads a variable the
    local class captured translates; translation crashed with a
    NullPointerException although --check found no problems.

  • A lambda that J2C reports instead of translating (such as one using this
    of an anonymous class) is no longer also reported, with a runtime, as a
    compile error about java.lang.invoke.LambdaMetafactory at line 1.

Unit tests

  • --tests translates JUnit 4 and 5 test classes and generates a GoogleTest
    wrapper for each runnable one, with JUnit's lifecycle order (including
    inherited methods), skipped disabled tests, and expected exceptions; the
    Makefile gains tests and test targets.
  • With --tests, --check reports test features the wrappers cannot run
    (mocking libraries, runners and extensions, parameterized or repeated tests,
    @Nested, timeouts, @TestInstance, private or parameterized methods).
    JUnit 4's @Test(timeout = ...) is reported too (it was missed when the
    timeout was written as an int).
  • JUnit assertions and assumptions (assertEquals with and without delta,
    assertTrue, assertNull, assertSame, assertArrayEquals, fail,
    assertThrows, assertDoesNotThrow, assumeTrue, and others) are
    translated into helpers that follow JUnit's rules and messages without a
    Java runtime. Other assertion forms are reported. Comparing JDK objects
    and showing custom messages need the runtime.
  • With --runtime, translated tests compare JDK objects (strings, boxed
    numbers, lists, maps) with Java's equals, and failure messages match
    JUnit's: values shown with toString, JUnit 5's message ==> prefix,
    Supplier<String> messages called only on failure, and JUnit 4's own
    forms (expected:<a> but was:<b>, strings compacted as
    ComparisonFailure does, its assertNull, assertSame, assertNotEquals
    and array messages). The AssertionError carries the message, and
    GoogleTest reports every exception's message. JUnit 4's assertions now
    translate into j2c::junit::junit4 helpers.
  • JUnit 4's @Test(expected = ...) failures use JUnit's messages
    (`Expected ...
Read more