mapstruct / mapstruct/mapstruct
Camelcase fields where the second letter is capitalized are not picked up
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 7.7k
- Forks
- 1.1k
- PR merge metrics
- No merged PRs in 30d
Description
Expected behavior
If a field name like xNameField is present in both source and target, MapStruct should recognize that field and generate a mapping for it, no matter whether the target class is using builders or not.
Actual behavior
If the target class provides a builder (generated via Lombok's @Builder) with a method TargetClass.TargetClassBuilder.xNameField(), MapStruct ignores that field completely.
Removing the builder from the target class or telling MapStruct not to use it (builder = @Builder(disableBuilder = true)) resolves the problem, although in the latter case, the generated code still is a bit weird:
public TargetClass map(SourceClass src) {
if ( src == null ) {
return null;
}
String someField = null;
String someOtherField = null;
someField = src.getSomeField();
someOtherField = src.getSomeOtherField();
String xNameField = null;
TargetClass targetClass = new TargetClass( someField, xNameField, someOtherField );
targetClass.setXNameField( src.getXNameField() );
return targetClass;
}
What also works is adding an explicit mapping with intentionally wrong capitalization, @Mapping(target = "xNameField", source = "XNameField") generates the correct mapping when it clearly shouldn't -- while @Mapping(target = "xNameField", source = "xNameField") causes an error "No property named "xNameField" exists in source parameter(s). Did you mean "XNameField"?"
Steps to reproduce the problem
Mapping source:
import lombok.Data;
@Data
public class SourceClass {
private String someField;
private String xName;
private String someOtherField;
}
Mapping target:
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class TargetClass {
private String someField;
private String xNameField;
private String someOtherField;
}
...and a simple mapper:
import org.mapstruct.Mapper;
@Mapper
public interface PocMapper {
TargetClass map(final SourceClass src);
}
Result is:
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2026-02-20T10:51:20+0100",
comments = "version: 1.6.3, compiler: javac, environment: Java 21.0.7 (Eclipse Adoptium)"
)
public class PocMapperImpl implements PocMapper {
@Override
public TargetClass map(SourceClass src) {
if ( src == null ) {
return null;
}
TargetClass.TargetClassBuilder targetClass = TargetClass.builder();
targetClass.someField( src.getSomeField() );
targetClass.someOtherField( src.getSomeOtherField() );
return targetClass.build();
}
}
What works
- Removing the
@BuilderfromTargetClass @Mapper(builder = @Builder(disableBuilder = true)), although MapStruct still seems to be a bit confused (see previous section)
What works, even though it clearly should not
- adding
@Mapping(target = "xNameField", source = "XNameField"), with a capital X in the source
What makes it even worse, even though it should work
- adding
@Mapping(target = "xNameField", source = "xNameField"), with the correct lower-case x in the source, lead to an error with the helpful suggestion to use "XNameField" instead
MapStruct Version
MapStruct 1.6.3
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the SourceClass, TargetClass, and PocMapper reproduction using MapStruct 1.6.3 and Lombok @Builder, then inspect the generated PocMapperImpl. Trace how the builder method named xNameField() is detected and compare generation with the builder enabled and disabled. Done means xNameField is mapped correctly in both cases without relying on an incorrectly capitalized explicit mapping.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend-api-design
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 65/100