Skip to content

Conversation

@DanielLiu1123
Copy link

Overview

Adds built-in support for Protocol Buffers generated classes in MapStruct. No more

@Mapper(collectionMappingStrategy = ADDER_PREFERRED, unmappedTargetPolicy = IGNORE)

Key Changes

1. ProtobufAccessorNamingStrategy

Custom accessor naming strategy that handles Protobuf-specific patterns:

  • Filters out Protobuf internal methods and auxiliary methods (e.g., getXxxBytes(), getXxxCount(), getXxxOrBuilder(), getXxxValue())
  • Recognizes getXxxList() for repeated fields
  • Recognizes getXxxMap() for map fields
  • Supports addAllXxx() and putAllXxx() as setters for collections

2. Type Conversions

Protobuf wrapper types ↔ Java primitives/objects:

  • BoolValue, StringValue, BytesValue
  • Int32Value, Int64Value, UInt32Value, UInt64Value
  • FloatValue, DoubleValue
  • ByteString ↔ byte array
  • ProtocolMessageEnum ↔ int

3. Built-in Mappings

Java time types ↔ Protobuf well-known/google.type:

  • Instantgoogle.protobuf.Timestamp
  • Durationgoogle.protobuf.Duration
  • LocalDategoogle.type.Date
  • LocalTimegoogle.type.TimeOfDay
  • DayOfWeekgoogle.type.DayOfWeek
  • Monthgoogle.type.Month

close #3073

Implemented comprehensive support for protobuf-generated classes with smart
accessor detection and code generation.

Core Features:
1. Protobuf Getter Recognition
   - getXxxList() → property "xxx" (repeated fields)
   - getXxxMap() → property "xxx" (map fields)

2. Repeated Field Support
   - Detects addXxx() methods for repeated fields
   - Generates loop-based adder calls instead of setters
   - Example: addItem(item) for List<Item> items

3. Map Field Support (NEW)
   - Added PUTTER accessor type for map operations
   - Detects putXxx(K, V) methods for map entries
   - Detects putAllXxx(Map) for bulk operations
   - Generates entry iteration with putter calls

Implementation Details:
- Extended MethodType enum with PUTTER type
- Extended AccessorType enum with PUTTER type
- Created ProtobufAccessorNamingStrategy for protobuf patterns
- Added getPutterForType() method in Type.java
- Created PutterWrapper and PutterWrapper.ftl for code generation
- Updated PropertyMapping to handle PUTTER accessor type
- Integrated putter selection into getPropertyWriteAccessors()

Technical Changes:
- processor/src/main/java/org/mapstruct/ap/spi/MethodType.java
- processor/src/main/java/org/mapstruct/ap/internal/util/accessor/AccessorType.java
- processor/src/main/java/org/mapstruct/ap/spi/ProtobufAccessorNamingStrategy.java (new)
- processor/src/main/java/org/mapstruct/ap/internal/util/AccessorNamingUtils.java
- processor/src/main/java/org/mapstruct/ap/internal/util/Filters.java
- processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java
- processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java
- processor/src/main/java/org/mapstruct/ap/internal/model/assignment/PutterWrapper.java (new)
- processor/src/main/resources/.../assignment/PutterWrapper.ftl (new)

Backward Compatibility:
- All changes are additive and non-breaking
- Default behavior preserved for non-protobuf classes
- Protobuf support activated via ProtobufAccessorNamingStrategy

🤖 Generated with Claude Code

Co-Authored-By: Claude <[email protected]>

refactor: Improve ProtobufAccessorNamingStrategy to only apply to MessageOrBuilder types

Based on the reference implementation from mapstruct-examples, this commit
adds proper type checking to ensure protobuf-specific logic is only applied
to Protocol Buffers generated classes.

Key Improvements:

1. MessageOrBuilder Type Detection
   - Initialize protobufMessageOrBuilderType in init() method
   - Check isProtobufType() before applying any protobuf-specific logic
   - Only classes implementing com.google.protobuf.MessageOrBuilder get special treatment

2. Protobuf Method Exclusions
   - Exclude getXxxBuilderList() methods (internal builder lists)
   - Exclude getXxxValueList() methods (internal value lists)
   - Exclude getAllFields() method (protobuf metadata)
   - Exclude methods with protobuf internal types as parameters
   - Exclude remove(int) methods (protobuf list manipulation)
   - Exclude mergeFrom() methods (protobuf internal)

3. Enhanced getElementName()
   - Append "List" suffix only for protobuf types
   - Matches protobuf convention: addItem() -> itemsList property
   - Append "Map" suffix for putter methods: putAttribute() -> attributesMap

4. Backward Compatibility
   - Non-protobuf classes use default behavior
   - All checks delegate to super methods first
   - Only add protobuf-specific filters on top

Implementation follows the pattern from:
https://github.com/mapstruct/mapstruct-examples/tree/main/mapstruct-on-gradle-protobuf3

🤖 Generated with Claude Code

Co-Authored-By: Claude <[email protected]>

Refactor: Treat protobuf map putters as ADDER type

Simplified architecture by removing the separate PUTTER method type
and treating map putter methods (e.g., putXxx(key, value)) as ADDER
type instead. This reduces code complexity while maintaining the same
functionality for protobuf map field mapping.

Changes:
- Removed PUTTER from MethodType and AccessorType enums
- Updated ProtobufAccessorNamingStrategy to return ADDER for putter methods
- Updated AccessorNamingUtils to accept 1 or 2 parameters for adders
- Removed putterMethodsIn from Filters
- Simplified Type.java by removing getPutters/getPutterForType methods
- Updated getAdderForType to handle both collections and maps
- Simplified PropertyMapping by removing assignToPlainViaPutter
- Updated assignToPlainViaAdder to handle maps with PutterWrapper

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>

test: Add tests for Protocol Buffers (protobuf) support

Added comprehensive tests to verify ProtobufAccessorNamingStrategy functionality:

Test Structure:
- Created mock com.google.protobuf.MessageOrBuilder interface for testing
- Created protobuf-style source classes with getXxxList() and getXxxMap() patterns
- Created target DTOs with standard JavaBeans accessors and adder/putter methods
- Registered ProtobufAccessorNamingStrategy in test resources META-INF/services

Tests:
- SimpleProtobufTest: Tests basic repeated field mapping (getItemsList -> addItem)
- ProtobufTest: Tests both repeated and map field mappings (currently partially working)

The tests verify that:
1. getXxxList() is recognized as getter for "xxx" property (repeated fields)
2. getXxxMap() is recognized as getter for "xxx" property (map fields)
3. addXxx() adder methods are used for repeated fields
4. putXxx() putter methods are used for map fields

Note: SimpleProtobufTest passes successfully, demonstrating that repeated
field support is working correctly with ProtobufAccessorNamingStrategy.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>

add docs

ref

ref

rm doc

revert

revert

revert

cpl error

no adder for pb

no adder for pb

handle enum

done

not support byte[]

add ProtobufEnumConversion

google/type pkg

rm DateTime support

adjust format

rm unused code

add protobufTest

add protobufTest

done

ref

ignore message set builder

const

fmt

add headler

inline

ref it

revert unnecessary changes

revert unnecessary changes

revert unnecessary changes

revert unnecessary changes

Add missing import
@DanielLiu1123
Copy link
Author

@filiphr Do you have time to take a look at this PR? It would be amazing if MapStruct could provide first-class support for protobuf.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

mapstruct native support protobuf

1 participant