Technical Documentation: google/j2objc
โน๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference
Overview (`README.md`)
J2ObjC: Java to Objective-C Translator and Runtime
Project site: https://j2objc.org
J2ObjC blog: https://j2objc.blogspot.com
Questions and discussion: https://groups.google.com/group/j2objc-discuss
What J2ObjC Is
J2ObjC is an open-source command-line tool from Google that translates
Java source code to Objective-C for the iOS (iPhone/iPad) platform. This tool
enables Java source to be part of an iOS application's build, as no editing
of the generated files is necessary. The goal is to write an app's non-UI
code (such as application logic and data models) in Java, which is then
shared by web apps (using GWT), Android apps,
and iOS apps.
J2ObjC supports most Java language and runtime features required by
client-side application developers, including exceptions, inner and
anonymous classes, generic types, threads and reflection. JUnit test
translation and execution is also supported.
J2ObjC is currently beta quality. Several Google projects rely on it, but
when new projects first start working with it, they usually find new bugs
to be fixed. If you run into issues with your project, please report them!
What J2ObjC isn't
J2ObjC does not provide any sort of platform-independent UI toolkit, nor are
there any plans to do so in the future. We believe that iOS UI code needs to
be written in Objective-C, Objective-C++ or Swift using Apple's iOS SDK (Android
UIs using Android's API, web app UIs using GWT, etc.).
J2ObjC cannot convert Android binary applications. Developers must have source
code for their Android app, which they either own or are licensed to use.
Requirements
- JDK 21
- Mac workstation or laptop
- OS X 15.6.1 or higher
- Xcode 16.3 or higher
License
This library is distributed under the Apache 2.0 license found in the
LICENSE file.
The protocol buffers library is distributed under the same BSD license as
Google's protocol buffers. See its
README and
LICENSE.
Running on GNU/Linux
To build and run on GNU/Linux, install the Darling project, then following its Compile and Run a Program example. Please note that j2objc is only supported on iOS/macOS.
Artifact Signatures
This project publishes some artifacts through Maven Central with a groupId of com.google.j2objc.
These artifacts are currently signed with [the following PGP/GPG key]
(https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xC3259D20DAEC4ACE6D57CC83340B090F727518D8):
---------
pub ed25519 2025-08-13 [SC] [expires: 2028-08-12]
C3259D20DAEC4ACE6D57CC83340B090F727518D8
uid [ultimate] Thomas Ball <[email protected]>
sub cv25519 2025-08-13 [E] [expires: 2028-08-12]Older artifacts are signed with the following PGP/GPG keys:
pub rsa2048 2023-01-10 [SC] [expires: 2025-01-09]
EB1B3DE71713C9EC2E87CC26EE92349AD86DE446
uid [ unknown] Thomas Ball <[email protected]>
sub rsa2048 2023-01-10 [E] [expires: 2025-01-09]pub rsa2048 2015-09-25 [SC]
B801E2F8EF035068EC1139CC29579F18FA8FD93B
uid [ unknown] Tom Ball <[email protected]>
sub rsa2048 2015-09-25 [E]Overview (`tree_shaker/README.md`)
J2ObjC Tree Shaker
About:
The tree shaker project is an experimental tool in the J2ObjC family that lets
users detect any unused code in their Java program. The purpose of the tool is
to provide the translator with a list of unused elements in the code that it
can remove to reduce the size of the translated project.
Usage:
The tree shaker can be used in two ways:
- Manual Analysis: Using the tree shaker by itself on a package of source
files, it will report a set of classes and methods that it detected as unused. - Dead Code Elimination in Translator: The tree-shaker-report output file,
generated by the tree shaker, can be used as an input to the translator, using
its Dead Code Elimination functionality (see the docs for translator). This
will automatically remove the unused code reported by the tree shaker from the
final translated source code.
Running Tree Shaker:
The tree shaker command takes in a few flags, as seen in the help message:
Usage: tree_shaker <options> <source files>
where possible options include:
-sourcepath <path> Specify where to find input source files.
-classpath <path> Specify where to find user class files.
--tree-shaker-roots Specify a file that lists the public root classes and methods.
-s, --sourcefilelist <file> Specify a file that lists the source files to be analyzed.
-encoding <encoding> Specify character encoding used by source files
-Xbootclasspath:<path> Boot path used to compile the input sources. (not the tool itself)
-version Version information
-Werror Treats all warning as errors.
-h, --help Print this message.All elements in the input source files that can be reached from the public
roots will be kept, and the others marked as unused. The input file formatting
for classes is the full packageName.className for the class, one class per line:
# These are the root classes for this library:
foo.bar.Mumble
itsy.bitsy.Spider
# Inner-classes work, too:
twisty.little.Passage.DirectionWhen indicating a class as a public root, the tree shaker will take all public
methods inside that class and add them to the public root set, for convenience.
To add specific methods to the public root set, add their enclosing class's
packageName.className, followed by a colon, and all of the root set methods
inside that class on the following lines, one on each line, preceded by 4
spaces. For example, this tells tree_shaker to only mark the main method as
used, which allows other methods to potentially be reported as dead:
my.little.Pony:
main(java.lang.String[])Ending Note:
The tree shaker tool is an experimental project, used at the user's own risk.
The manual analysis use case is completely safe, and is the recommended way to
analyze source code for unused elements while the tree shaker is still in
testing. More adventurous users are encouraged to experiment with dead code
elimination, find and/or fix bugs, and submit pull requests.
Overview (`jre_emul/junit_tests/README.md`)
JRE JUnit Tests
This is a simple iOS app that redirects System.out and System.err to a
scrollable panel, then runs the JUnit tests for the
J2ObjC's JRE library as a background task. Test output is also saved as
a file on the iOS device, which can be uploaded from Xcode's Organizer
window.
App Icons
The project's app icons for this app were created using
GIMP for Mac OS X, then converted into iOS
icons using the Macappicon app icon generator. To
update the icons to the lastest iOS requirements, drag the junit-tests-logo.png
file to MakeAppIcon's toaster, enter your email when it's created the icon set
and it will be mailed to your account. Unzip the icon set and copy
ios/AppIcon.appiconset to j2objc/jre_emul/junit_tests/Images.xcassets/.
Reuse and Improve
Feel free to clone this app and change it to run your app's JUnit tests.
We're also very interested in any improvements that would help make testing
easier.
Overview (`jre_emul/android/platform/external/okhttp/okio/README.md`)
Okio
Okio is a new library that complements java.io and java.nio to make it much
easier to access, store, and process your data.
ByteStrings and Buffers
Okio is built around two types that pack a lot of capability into a
straightforward API:
ByteString is an immutable sequence of bytes. For character data,
String
is fundamental.ByteStringis String's long-lost brother, making it easy to
treat binary data as a value. This class is ergonomic: it knows how to encode
and decode itself as hex, base64, and UTF-8.Buffer is a mutable sequence of bytes. Like
ArrayList, you don't need
to size your buffer in advance. You read and write buffers as a queue: write
data to the end and read it from the front. There's no obligation to manage
positions, limits, or capacities.
Internally, ByteString and Buffer do some clever things to save CPU and
memory. If you encode a UTF-8 string as a ByteString, it caches a reference to
that string so that if you decode it later, there's no work to do.
Buffer is implemented as a linked list of segments. When you move data from
one buffer to another, it reassigns ownership of the segments rather than
copying the data across. This approach is particularly helpful for multithreaded
programs: a thread that talks to the network can exchange data with a worker
thread without any copying or ceremony.
Sources and Sinks
An elegant part of the java.io design is how streams can be layered for
transformations like encryption and compression. Okio includes its own stream
types called Source and Sink that work like InputStream andOutputStream, but with some key differences:
Timeouts. The streams provide access to the timeouts of the underlying
I/O mechanism. Unlike thejava.iosocket streams, bothread()andwrite()calls honor timeouts.Easy to implement.
Sourcedeclares three methods:read(),close(),
andtimeout(). There are no hazards likeavailable()or single-byte reads
that cause correctness and performance surprises.Easy to use. Although implementations of
SourceandSinkhave only
three methods to write, callers are given a rich API with theBufferedSourceandBufferedSinkinterfaces. These interfaces give you
everything you need in one place.No artificial distinction between byte streams and char streams. It's all
data. Read and write it as bytes, UTF-8 strings, big-endian 32-bit integers,
little-endian shorts; whatever you want. No moreInputStreamReader!Easy to test. The
Bufferclass implements bothBufferedSourceandBufferedSinkso your test code is simple and clear.
Sources and sinks interoperate with InputStream and OutputStream. You can
view any Source as an InputStream, and you can view any InputStream as aSource. Similarly for Sink and OutputStream.
Dependable
Okio started as a component of OkHttp, the capable HTTP+SPDY client
included in Android. It's well-exercised and ready to solve new problems.
Example: a PNG decoder
Decoding the chunks of a PNG file demonstrates Okio in practice.
private static final ByteString PNG_HEADER = ByteString.decodeHex("89504e470d0a1a0a");
public void decodePng(InputStream in) throws IOException {
BufferedSource pngSource = Okio.buffer(Okio.source(in));
ByteString header = pngSource.readByteString(PNG_HEADER.size());
if (!header.equals(PNG_HEADER)) {
throw new IOException("Not a PNG.");
}
while (true) {
Buffer chunk = new Buffer();
// Each chunk is a length, type, data, and CRC offset.
int length = pngSource.readInt();
String type = pngSource.readUtf8(4);
pngSource.readFully(chunk, length);
int crc = pngSource.readInt();
decodeChunk(type, chunk);
if (type.equals("IEND")) break;
}
pngSource.close();
}
private void decodeChunk(String type, Buffer chunk) {
if (type.equals("IHDR")) {
int width = chunk.readInt();
int height = chunk.readInt();
System.out.printf("%08x: %s %d x %d%n", chunk.size(), type, width, height);
} else {
System.out.printf("%08x: %s%n", chunk.size(), type);
}
}Download
Download the latest JAR or grab via Maven:
<dependency>
<groupId>com.squareup.okio</groupId>
<artifactId>okio</artifactId>
<version>1.6.0</version>
</dependency>or Gradle:
compile 'com.squareup.okio:okio:1.6.0'Snapshots of the development version are available in Sonatype's snapshots repository.
--- METRICS ---
- Files Extracted: 4
- Estimated Token Budget: ~3247 tokens
- Canonical Reference: https://codewiki.google/github.com/google/j2objc