Prettier plugin for formatting Java code with automatic style rules and IDE integration
npx @tessl/cli install tessl/npm-prettier-plugin-java@2.7.0Prettier Plugin Java provides automatic code formatting for Java source files through Prettier's extensible plugin system. It uses a JavaScript-based Java parser to format Java code without requiring a Java runtime, making it ideal for integration into modern development workflows, IDEs, and CI/CD pipelines.
npm install prettier-plugin-java --save-devESM Import:
import plugin from "prettier-plugin-java";CommonJS Import:
const plugin = require("prettier-plugin-java");Format Java files directly using Prettier CLI:
# Format a single file
prettier --write MyJavaFile.java
# Format all Java files in src directory
prettier --write "src/**/*.java"
# Format with specific entrypoint for code snippets
prettier --write MyJavaSnippet.java --entrypoint methodDeclarationUse Prettier's API with the plugin to format Java code:
import { format } from "prettier";
import plugin from "prettier-plugin-java";
const javaCode = `
public class HelloWorld {
public static void main(String[] args) {System.out.println("Hello World!");;;;;}
@Override
public String toString() {
return "Hello World";
}
public int sum(int argument1,int argument2,int argument3,int argument4,int argument5
) {
return argument1+argument2+ argument3 +argument4 + argument5;
}
}
`;
const formattedCode = await format(javaCode, {
parser: "java",
plugins: [plugin],
tabWidth: 2,
printWidth: 80
});
console.log(formattedCode);The plugin is built around the Prettier plugin architecture with these key components:
The main plugin object that integrates with Prettier's formatting system.
/**
* Main plugin export implementing Prettier's Plugin interface
*/
declare const plugin: Plugin<JavaNode>;
interface Plugin<T> {
/** Language definitions supported by the plugin */
languages: LanguageSupport[];
/** Parser configurations keyed by parser name */
parsers: Record<string, Parser<T>>;
/** Printer configurations keyed by printer name */
printers: Record<string, Printer<T>>;
/** Plugin-specific formatting options */
options: SupportOptions;
/** Default option values for the plugin */
defaultOptions: Record<string, any>;
}
interface LanguageSupport {
/** Display name of the language */
name: string;
/** List of parser names that can handle this language */
parsers: string[];
/** Language group for IDE integration */
group: string;
/** TextMate scope identifier */
tmScope: string;
/** Ace editor mode */
aceMode: string;
/** CodeMirror mode */
codemirrorMode: string;
/** CodeMirror MIME type */
codemirrorMimeType: string;
/** File extensions handled by this language */
extensions: string[];
/** GitHub Linguist language ID */
linguistLanguageId: number;
/** VS Code language identifiers */
vscodeLanguageIds: string[];
}Parses Java source code into a Concrete Syntax Tree using the java-parser library.
/**
* Java parser that converts source code to CST
*/
interface JavaParser extends Parser<JavaNode> {
/** Parse Java source code to CST */
parse(text: string, options: JavaParserOptions): JavaNonTerminal;
/** AST format identifier */
astFormat: "java";
/** Check for prettier pragma comments */
hasPragma(text: string): boolean;
/** Get start location of a node */
locStart(node: JavaNode): number;
/** Get end location of a node */
locEnd(node: JavaNode): number;
}
interface JavaParserOptions extends ParserOptions<JavaNode> {
/** Grammar entrypoint for parsing code snippets */
entrypoint?: string;
}Converts the parsed CST back to formatted Java source code.
/**
* Java printer that converts CST to formatted source code
*/
interface JavaPrinter extends Printer<JavaNode> {
/** Main printing function for formatting nodes */
print(
path: AstPath<JavaNode>,
options: any,
print: (path: AstPath<JavaNode>) => Doc,
args?: any
): Doc;
/** Check if node should be ignored by prettier */
hasPrettierIgnore(path: AstPath<JavaNode>): boolean;
/** Determine if comments can be attached to nodes */
canAttachComment(node: JavaNode): boolean;
/** Identify block comments vs line comments */
isBlockComment(node: JavaNode): boolean;
/** Format comment nodes */
printComment(commentPath: AstPath<JavaNode>): string;
/** Get child nodes for comment processing */
getCommentChildNodes(node: JavaNode): JavaNode[];
/** Comment handling strategies */
handleComments: {
ownLine: (commentPath: AstPath<JavaNode>) => boolean;
endOfLine: (commentPath: AstPath<JavaNode>) => boolean;
remaining: (commentPath: AstPath<JavaNode>) => boolean;
};
}Plugin-specific options for customizing Java code formatting behavior.
/**
* Java-specific formatting options
*/
interface JavaFormattingOptions extends SupportOptions {
/** Grammar entrypoint for parsing code snippets */
entrypoint: {
type: "choice";
category: "Global";
default: "compilationUnit";
/** 250+ Java grammar rules for parsing different code constructs */
choices: Array<{
value: string;
description: string;
}>;
description: "Prettify from the entrypoint, allowing to use prettier on snippet";
};
/** Arrow function parentheses handling */
arrowParens: {
type: "choice";
category: "Java";
default: "always";
choices: Array<{ value: "always" | "avoid"; description: string }>;
description: "Include parentheses around a sole arrow function parameter";
};
/** Trailing comma configuration */
trailingComma: {
type: "choice";
category: "Java";
default: "all";
choices: Array<{ value: "all" | "es5" | "none"; description: string }>;
description: "Print trailing commas wherever possible when multi-line";
};
/** Binary operator positioning */
experimentalOperatorPosition: {
type: "choice";
category: "Java";
default: "end";
choices: Array<{ value: "start" | "end"; description: string }>;
description: "Where to print operators when binary expressions wrap lines";
};
}Available Entrypoints (Grammar Rules):
The plugin supports 250+ Java grammar entrypoints for formatting code snippets. Key entrypoints include:
compilationUnit (default) - Complete Java source filesclassDeclaration - Class definitionsmethodDeclaration - Method definitionsclassBodyDeclaration - Class member declarationsstatement - Individual statementsexpression - Expressionsblock - Code blocksvariableDeclaration - Variable declarationsannotation - AnnotationsinterfaceDeclaration - Interface definitionsHandles Java comments, prettier directives, and formatter regions.
/**
* Comment processing and formatter directive handling
*/
interface CommentProcessor {
/** Process @formatter:off/on comment directives */
determineFormatterOffOnRanges(cst: JavaNonTerminal): void;
/** Check if node is within formatter-off region */
isFullyBetweenFormatterOffOn(path: AstPath<JavaNode>): boolean;
/** Determine if comments can be attached to a node */
canAttachComment(node: JavaNode): boolean;
/** Handle line comments (// and /* */) */
handleLineComment(commentPath: AstPath<JavaNode>): boolean;
/** Handle remaining unprocessed comments */
handleRemainingComment(commentPath: AstPath<JavaNode>): boolean;
}
interface JavaComment {
/** Comment text content */
image: string;
/** Comment value (same as image) */
value: string;
/** Start position in source */
startOffset: number;
/** End position in source */
endOffset: number;
/** Whether this is a leading comment */
leading: boolean;
/** Whether this is a trailing comment */
trailing: boolean;
/** Comment token type */
tokenType: {
name: string;
GROUP: string;
};
}Supported Comment Directives:
// prettier-ignore - Skip formatting for next statement/* prettier-ignore */ - Skip formatting for next statement// @formatter:off - Disable formatting until @formatter:on/* @formatter:off */ - Disable formatting until @formatter:on// @formatter:on - Re-enable formatting/* @formatter:on */ - Re-enable formattingCore type definitions for Java AST nodes used throughout the plugin.
/**
* Core Java AST node types
*/
type JavaNode = CstElement & {
/** Attached comments for this node */
comments?: JavaComment[]
};
/** Non-terminal AST nodes (containers) */
type JavaNonTerminal = Exclude<JavaNode, IToken>;
/** Terminal AST nodes (tokens) */
type JavaTerminal = Exclude<JavaNode, CstNode>;
/** Type-safe printer function */
type JavaPrintFn = (path: AstPath<JavaNode>, args?: unknown) => Doc;
/** Node-specific printer function */
type JavaNodePrinter<T> = (
path: AstPath<Extract<JavaNonTerminal, { name: T }>>,
print: JavaPrintFn,
options: JavaParserOptions,
args?: unknown
) => Doc;
/** Collection of all node-specific printers */
type JavaNodePrinters = {
[T in JavaNonTerminal["name"]]: JavaNodePrinter<T>;
};Helper functions for AST manipulation and formatting logic.
/**
* AST manipulation and formatting utilities
*/
interface PluginUtilities {
/** Extract single defined key from object */
onlyDefinedKey<T extends Record<string, any>>(
obj: T,
options?: string[]
): string;
/** Get all defined keys from object */
definedKeys<T extends Record<string, any>>(
obj: T,
options?: string[]
): string[];
/** Sort Java modifiers in standard order */
sortModifiers(modifiers: string[]): string[];
/** Format class type expressions with generics */
printClassType(
path: AstPath<JavaNonTerminal>,
print: JavaPrintFn
): Doc;
/** Check if expression is a binary expression */
isBinaryExpression(expression: ExpressionCstNode): boolean;
/** Check if statement is empty */
isEmptyStatement(statement: StatementCstNode): boolean;
/** Type guard for non-terminal nodes */
isNonTerminal(node: CstElement): node is JavaNonTerminal;
/** Type guard for terminal nodes */
isTerminal(node: CstElement): node is IToken;
/** Calculate base indentation for multi-line strings */
findBaseIndent(lines: string[]): number;
}# Install the plugin
npm install prettier-plugin-java --save-dev
# Format a Java file
prettier --write src/main/java/com/example/MyClass.java
# Format all Java files in a project
prettier --write "src/**/*.java"import { format } from "prettier";
import plugin from "prettier-plugin-java";
// Format a method declaration snippet
const methodSnippet = `
public void myMethod() {
myObject.is().very().very().very().very().long().chain();
}
`;
const formatted = await format(methodSnippet, {
parser: "java",
plugins: [plugin],
entrypoint: "classBodyDeclaration",
printWidth: 80
});import { format } from "prettier";
import plugin from "prettier-plugin-java";
const javaCode = `
public class Example {
public void method(int a,int b,int c) {
return a+b+c;
}
}
`;
const formatted = await format(javaCode, {
parser: "java",
plugins: [plugin],
// Java-specific options
entrypoint: "compilationUnit",
arrowParens: "always",
trailingComma: "all",
experimentalOperatorPosition: "end",
// Standard Prettier options
tabWidth: 4,
printWidth: 120,
useTabs: false
});package.json scripts:
{
"scripts": {
"format": "prettier --write \"src/**/*.java\"",
"format:check": "prettier --check \"src/**/*.java\""
}
}Pre-commit hook with husky:
{
"husky": {
"hooks": {
"pre-commit": "prettier --write \"src/**/*.java\" && git add ."
}
}
}import { format } from "prettier";
import plugin from "prettier-plugin-java";
try {
const formatted = await format(invalidJavaCode, {
parser: "java",
plugins: [plugin]
});
} catch (error) {
if (error.name === "SyntaxError") {
console.error("Java syntax error:", error.message);
} else {
console.error("Formatting error:", error.message);
}
}/**
* Complete type definitions for prettier-plugin-java
*/
import type { Plugin, Parser, Printer, AstPath, Doc, ParserOptions, SupportOptions } from "prettier";
import type { CstElement, CstNode, IToken } from "java-parser";
/** Main plugin interface */
declare const plugin: Plugin<JavaNode>;
/** Java AST node with optional comments */
type JavaNode = CstElement & { comments?: JavaComment[] };
/** Non-terminal nodes (containers) */
type JavaNonTerminal = Exclude<JavaNode, IToken>;
/** Terminal nodes (tokens) */
type JavaTerminal = Exclude<JavaNode, CstNode>;
/** Parser options with Java-specific entrypoint */
interface JavaParserOptions extends ParserOptions<JavaNode> {
entrypoint?: string;
}
/** Type-safe print function */
type JavaPrintFn = (path: AstPath<JavaNode>, args?: unknown) => Doc;
/** Comment attached to AST nodes */
interface JavaComment {
/** Comment text content */
image: string;
/** Comment value (same as image) */
value: string;
/** Start position in source */
startOffset: number;
/** End position in source */
endOffset: number;
/** Whether this is a leading comment */
leading: boolean;
/** Whether this is a trailing comment */
trailing: boolean;
/** Comment token type */
tokenType: {
name: string;
GROUP: string;
};
}export default plugin;