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
31 changes: 6 additions & 25 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,35 +8,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Added
- Comprehensive README with usage examples and generated Java code samples
- Installation instructions for pip and source installation
- Examples covering all major features:
- Basic class, interface, and enum creation
- Generic types and type variables
- Annotations and Javadoc
- Complex control flow structures
- Records (Java 14+)
- File I/O operations
- Enhanced TypeName support for common Java library types (List, Map, Set, etc.)
- Better Python type mapping (bool -> boolean, int -> int, etc.)
- Added `add_javadoc` method alongside existing `add_javadoc_line`
- Added `add_raw_line` method for raw code with newlines
- Support for handling None values in TypeName.get()
- N/A

### Changed
- Updated README structure with clear Python-to-Java code mappings
- Enhanced documentation with working examples
- Improved TypeName.get() to handle Python types directly (e.g., `TypeName.get(bool)` returns `TypeName.BOOLEAN`)
- Updated method API: `add_code()` renamed to `add_raw_code()` for clarity
- Enhanced JavaDoc generation with better newline handling
- Fixed annotation newline formatting issues
- Improved static class name handling
- N/A

### Fixed
- TypeName.get() now properly handles Python type objects instead of just type names
- JavaDoc emission now properly handles newlines and prefixes
- Annotation formatting with correct newline placement
- Primitive type boxing to proper wrapper classes (e.g., int -> java.lang.Integer)
- N/A

## [0.1.3] - 2025-08-04
- Moved all common ClassNames to be under ClassName instead of TypeName

## [0.1.2] - 2025-08-03

Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -565,10 +565,10 @@ print(str(TypeName.get("boolean"))) # Output: boolean
print(str(TypeName.get("void"))) # Output: void

# Predefined constants
print(str(TypeName.INT)) # Output: int
print(str(TypeName.BOOLEAN)) # Output: boolean
print(str(TypeName.VOID)) # Output: void
print(str(TypeName.STRING)) # Output: java.lang.String
print(str(ClassName.INT)) # Output: int
print(str(ClassName.BOOLEAN)) # Output: boolean
print(str(ClassName.VOID)) # Output: void
print(str(ClassName.STRING)) # Output: java.lang.String
```

#### ArrayTypeName
Expand Down
6 changes: 3 additions & 3 deletions examples/complex_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def main():
override_annotation = ClassName.get("java.lang", "Override")

# Create a field for the processor name
name_field = FieldSpec.builder(TypeName.STRING, "name").add_modifiers(Modifier.PRIVATE, Modifier.FINAL).build()
name_field = FieldSpec.builder(ClassName.STRING, "name").add_modifiers(Modifier.PRIVATE, Modifier.FINAL).build()

# Create a counter field
counter_field = (
Expand All @@ -65,7 +65,7 @@ def main():
constructor = (
MethodSpec.constructor_builder()
.add_modifiers(Modifier.PUBLIC)
.add_parameter(TypeName.STRING, "name")
.add_parameter(ClassName.STRING, "name")
.add_statement("this.$N = $T.requireNonNull($N)", "name", objects_class, "name")
.build()
)
Expand Down Expand Up @@ -95,7 +95,7 @@ def main():
MethodSpec.method_builder("toString")
.add_annotation(AnnotationSpec.get(override_annotation))
.add_modifiers(Modifier.PUBLIC)
.returns(TypeName.STRING)
.returns(ClassName.STRING)
.add_statement("return $S + name + $S + processCount + $S", "DataProcessor{name='", "', processCount=", "}")
.build()
)
Expand Down
218 changes: 109 additions & 109 deletions pyjavapoet/type_name.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,58 +34,6 @@ class TypeName(ABC):
Base class for types in Java's type system.
"""

INTEGER: "ClassName"
LONG: "ClassName"
DOUBLE: "ClassName"
FLOAT: "ClassName"
SHORT: "ClassName"
BYTE: "ClassName"
CHAR: "ClassName"
BOOLEAN: "ClassName"
VOID: "ClassName"
OBJECT: "ClassName"
STRING: "ClassName"
VOID: "ClassName"
LIST: "ClassName"
MAP: "ClassName"
SET: "ClassName"

# Commonly used Java library types
LIST: "ClassName"
MAP: "ClassName"
SET: "ClassName"
COLLECTION: "ClassName"
ITERABLE: "ClassName"
ITERATOR: "ClassName"
OPTIONAL: "ClassName"
STREAM: "ClassName"
ARRAY_LIST: "ClassName"
LINKED_LIST: "ClassName"
HASH_MAP: "ClassName"
LINKED_HASH_MAP: "ClassName"
TREE_MAP: "ClassName"
HASH_SET: "ClassName"
LINKED_HASH_SET: "ClassName"
TREE_SET: "ClassName"
QUEUE: "ClassName"
DEQUE: "ClassName"
STACK: "ClassName"
VECTOR: "ClassName"
ENUM_SET: "ClassName"
ENUM_MAP: "ClassName"
BIG_DECIMAL: "ClassName"
BIG_INTEGER: "ClassName"
DATE: "ClassName"
CALENDAR: "ClassName"
LOCALE: "ClassName"
FILE: "ClassName"
PATH: "ClassName"
URL: "ClassName"
UUID: "ClassName"
OBJECTS: "ClassName"
STRING_BUILDER: "ClassName"
STRING_BUFFER: "ClassName"

# Primitive types mapping
PRIMITIVE_TYPES = {
"boolean": "Boolean",
Expand Down Expand Up @@ -179,7 +127,7 @@ def is_any_primitive(self) -> bool:
@staticmethod
def get(type_mirror_or_name: Union[str, type, "TypeName", None]) -> "TypeName":
if not type_mirror_or_name:
return TypeName.VOID
return ClassName.VOID

if isinstance(type_mirror_or_name, TypeName):
return type_mirror_or_name
Expand All @@ -197,24 +145,76 @@ def get(type_mirror_or_name: Union[str, type, "TypeName", None]) -> "TypeName":
if isinstance(type_mirror_or_name, type):
# Map Python types to Java types
type_mapping = {
bool: TypeName.BOOLEAN,
int: TypeName.INTEGER,
float: TypeName.FLOAT,
str: TypeName.STRING,
list: TypeName.LIST,
dict: TypeName.MAP,
set: TypeName.SET,
tuple: TypeName.LIST,
bool: ClassName.BOOLEAN,
int: ClassName.INTEGER,
float: ClassName.FLOAT,
str: ClassName.STRING,
list: ClassName.LIST,
dict: ClassName.MAP,
set: ClassName.SET,
tuple: ClassName.LIST,
}

if type_mirror_or_name in type_mapping:
return TypeName.get(type_mapping[type_mirror_or_name])
else:
# Default to Java Object for other Python types
return TypeName.OBJECT
return ClassName.OBJECT


class ClassName(TypeName):
INTEGER: "ClassName"
LONG: "ClassName"
DOUBLE: "ClassName"
FLOAT: "ClassName"
SHORT: "ClassName"
BYTE: "ClassName"
CHAR: "ClassName"
BOOLEAN: "ClassName"
VOID: "ClassName"
OBJECT: "ClassName"
STRING: "ClassName"
VOID: "ClassName"
LIST: "ClassName"
MAP: "ClassName"
SET: "ClassName"

# Commonly used Java library types
LIST: "ClassName"
MAP: "ClassName"
SET: "ClassName"
COLLECTION: "ClassName"
ITERABLE: "ClassName"
ITERATOR: "ClassName"
OPTIONAL: "ClassName"
STREAM: "ClassName"
ARRAY_LIST: "ClassName"
LINKED_LIST: "ClassName"
HASH_MAP: "ClassName"
LINKED_HASH_MAP: "ClassName"
TREE_MAP: "ClassName"
HASH_SET: "ClassName"
LINKED_HASH_SET: "ClassName"
TREE_SET: "ClassName"
QUEUE: "ClassName"
DEQUE: "ClassName"
STACK: "ClassName"
VECTOR: "ClassName"
ENUM_SET: "ClassName"
ENUM_MAP: "ClassName"
BIG_DECIMAL: "ClassName"
BIG_INTEGER: "ClassName"
DATE: "ClassName"
CALENDAR: "ClassName"
LOCALE: "ClassName"
FILE: "ClassName"
PATH: "ClassName"
URL: "ClassName"
UUID: "ClassName"
OBJECTS: "ClassName"
STRING_BUILDER: "ClassName"
STRING_BUFFER: "ClassName"

package_name: str
simple_names: list[str]
ignore_import: bool
Expand Down Expand Up @@ -499,7 +499,7 @@ def __init__(
annotations: list["AnnotationSpec"] | None = None,
):
super().__init__(annotations)
self.upper_bounds = upper_bounds or [TypeName.OBJECT]
self.upper_bounds = upper_bounds or [ClassName.OBJECT]
self.lower_bounds = lower_bounds or []

def emit(self, code_writer) -> None:
Expand All @@ -512,7 +512,7 @@ def emit(self, code_writer) -> None:
code_writer.emit("?")

# Emit bounds
if len(self.upper_bounds) == 1 and TypeName.OBJECT is not None and self.upper_bounds[0] == TypeName.OBJECT:
if len(self.upper_bounds) == 1 and ClassName.OBJECT is not None and self.upper_bounds[0] == ClassName.OBJECT:
# Unbounded wildcard or has lower bounds
pass
else:
Expand Down Expand Up @@ -547,48 +547,48 @@ def supertypes_of(*lower_bounds: Union["TypeName", str, type]) -> "WildcardTypeN
return WildcardTypeName(lower_bounds=[TypeName.get(bound) for bound in lower_bounds])


TypeName.INTEGER = ClassName.get("", "int")
TypeName.LONG = ClassName.get("", "long")
TypeName.DOUBLE = ClassName.get("", "double")
TypeName.FLOAT = ClassName.get("", "float")
TypeName.SHORT = ClassName.get("", "short")
TypeName.BYTE = ClassName.get("", "byte")
TypeName.CHAR = ClassName.get("", "char")
TypeName.BOOLEAN = ClassName.get("", "boolean")
TypeName.VOID = ClassName.get("", "void")
TypeName.OBJECT = ClassName.get("java.lang", "Object")
TypeName.STRING = ClassName.get("java.lang", "String")
TypeName.LIST = ClassName.get("java.util", "List")
TypeName.MAP = ClassName.get("java.util", "Map")
TypeName.SET = ClassName.get("java.util", "Set")
TypeName.COLLECTION = ClassName.get("java.util", "Collection")
TypeName.ITERABLE = ClassName.get("java.lang", "Iterable")
TypeName.ITERATOR = ClassName.get("java.util", "Iterator")
TypeName.OPTIONAL = ClassName.get("java.util", "Optional")
TypeName.STREAM = ClassName.get("java.util.stream", "Stream")
TypeName.ARRAY_LIST = ClassName.get("java.util", "ArrayList")
TypeName.LINKED_LIST = ClassName.get("java.util", "LinkedList")
TypeName.HASH_MAP = ClassName.get("java.util", "HashMap")
TypeName.LINKED_HASH_MAP = ClassName.get("java.util", "LinkedHashMap")
TypeName.TREE_MAP = ClassName.get("java.util", "TreeMap")
TypeName.HASH_SET = ClassName.get("java.util", "HashSet")
TypeName.LINKED_HASH_SET = ClassName.get("java.util", "LinkedHashSet")
TypeName.TREE_SET = ClassName.get("java.util", "TreeSet")
TypeName.QUEUE = ClassName.get("java.util", "Queue")
TypeName.DEQUE = ClassName.get("java.util", "Deque")
TypeName.STACK = ClassName.get("java.util", "Stack")
TypeName.VECTOR = ClassName.get("java.util", "Vector")
TypeName.ENUM_SET = ClassName.get("java.util", "EnumSet")
TypeName.ENUM_MAP = ClassName.get("java.util", "EnumMap")
TypeName.BIG_DECIMAL = ClassName.get("java.math", "BigDecimal")
TypeName.BIG_INTEGER = ClassName.get("java.math", "BigInteger")
TypeName.DATE = ClassName.get("java.util", "Date")
TypeName.CALENDAR = ClassName.get("java.util", "Calendar")
TypeName.LOCALE = ClassName.get("java.util", "Locale")
TypeName.FILE = ClassName.get("java.io", "File")
TypeName.PATH = ClassName.get("java.nio.file", "Path")
TypeName.URL = ClassName.get("java.net", "URL")
TypeName.UUID = ClassName.get("java.util", "UUID")
TypeName.OBJECTS = ClassName.get("java.util", "Objects")
TypeName.STRING_BUILDER = ClassName.get("java.lang", "StringBuilder")
TypeName.STRING_BUFFER = ClassName.get("java.lang", "StringBuffer")
ClassName.INTEGER = ClassName.get("", "int")
ClassName.LONG = ClassName.get("", "long")
ClassName.DOUBLE = ClassName.get("", "double")
ClassName.FLOAT = ClassName.get("", "float")
ClassName.SHORT = ClassName.get("", "short")
ClassName.BYTE = ClassName.get("", "byte")
ClassName.CHAR = ClassName.get("", "char")
ClassName.BOOLEAN = ClassName.get("", "boolean")
ClassName.VOID = ClassName.get("", "void")
ClassName.OBJECT = ClassName.get("java.lang", "Object")
ClassName.STRING = ClassName.get("java.lang", "String")
ClassName.LIST = ClassName.get("java.util", "List")
ClassName.MAP = ClassName.get("java.util", "Map")
ClassName.SET = ClassName.get("java.util", "Set")
ClassName.COLLECTION = ClassName.get("java.util", "Collection")
ClassName.ITERABLE = ClassName.get("java.lang", "Iterable")
ClassName.ITERATOR = ClassName.get("java.util", "Iterator")
ClassName.OPTIONAL = ClassName.get("java.util", "Optional")
ClassName.STREAM = ClassName.get("java.util.stream", "Stream")
ClassName.ARRAY_LIST = ClassName.get("java.util", "ArrayList")
ClassName.LINKED_LIST = ClassName.get("java.util", "LinkedList")
ClassName.HASH_MAP = ClassName.get("java.util", "HashMap")
ClassName.LINKED_HASH_MAP = ClassName.get("java.util", "LinkedHashMap")
ClassName.TREE_MAP = ClassName.get("java.util", "TreeMap")
ClassName.HASH_SET = ClassName.get("java.util", "HashSet")
ClassName.LINKED_HASH_SET = ClassName.get("java.util", "LinkedHashSet")
ClassName.TREE_SET = ClassName.get("java.util", "TreeSet")
ClassName.QUEUE = ClassName.get("java.util", "Queue")
ClassName.DEQUE = ClassName.get("java.util", "Deque")
ClassName.STACK = ClassName.get("java.util", "Stack")
ClassName.VECTOR = ClassName.get("java.util", "Vector")
ClassName.ENUM_SET = ClassName.get("java.util", "EnumSet")
ClassName.ENUM_MAP = ClassName.get("java.util", "EnumMap")
ClassName.BIG_DECIMAL = ClassName.get("java.math", "BigDecimal")
ClassName.BIG_INTEGER = ClassName.get("java.math", "BigInteger")
ClassName.DATE = ClassName.get("java.util", "Date")
ClassName.CALENDAR = ClassName.get("java.util", "Calendar")
ClassName.LOCALE = ClassName.get("java.util", "Locale")
ClassName.FILE = ClassName.get("java.io", "File")
ClassName.PATH = ClassName.get("java.nio.file", "Path")
ClassName.URL = ClassName.get("java.net", "URL")
ClassName.UUID = ClassName.get("java.util", "UUID")
ClassName.OBJECTS = ClassName.get("java.util", "Objects")
ClassName.STRING_BUILDER = ClassName.get("java.lang", "StringBuilder")
ClassName.STRING_BUFFER = ClassName.get("java.lang", "StringBuffer")
4 changes: 1 addition & 3 deletions pyjavapoet/type_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,9 +345,7 @@ def record_builder(name: str) -> "Builder":

@staticmethod
def anonymous_class_builder(format_string: str = "", *args) -> "AnonymousClassBuilder":
from pyjavapoet.type_name import TypeName

builder = TypeSpec.AnonymousClassBuilder(TypeName.OBJECT)
builder = TypeSpec.AnonymousClassBuilder(ClassName.OBJECT)
if format_string:
builder.add_super_class_constructor_argument(format_string, *args)
return builder
Expand Down
4 changes: 2 additions & 2 deletions tests/test_class_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from pyjavapoet.java_file import JavaFile
from pyjavapoet.method_spec import MethodSpec
from pyjavapoet.modifier import Modifier
from pyjavapoet.type_name import TypeName, TypeVariableName
from pyjavapoet.type_name import ClassName, TypeVariableName
from pyjavapoet.type_spec import TypeSpec


Expand All @@ -33,7 +33,7 @@ def test_interface(self):
"""Test generating an interface."""
# Create a constant field
constant = (
FieldSpec.builder(TypeName.STRING, "ONLY_THING_THAT_IS_CONSTANT")
FieldSpec.builder(ClassName.STRING, "ONLY_THING_THAT_IS_CONSTANT")
.add_modifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
.initializer("$S", "change")
.build()
Expand Down
Loading
Loading