Prettier plugin for formatting Java code with automatic style rules and IDE integration
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Prettier 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;
Install with Tessl CLI
npx tessl i tessl/npm-prettier-plugin-java