MapStruct 不检测构建器中的设置器
MapStruct does not detect setters in builder
我正在使用 spring 构建一个简单的 REST 服务。我将我的实体与 DTO 分开,并使用 Immutables. I needed mapping between DTOs and DAOs, so I chose MapStruct 使 DTO 不可变。 Mapper 无法检测到我在 DAO 中定义的设置器。
问题与. This question does not have an accepted answer and I have tried all of the suggestions in that question and they don't work. I don't want to try because I feel it defeats the purpose for which I am using Immutables. @marc-von-renteln summarizes this reason nicely in the comment
一模一样
我尝试了@tobias-schulte 提供的。但这引起了另一个问题。在 Mapper class 的答案中,尝试从映射方法 return Immutable*.Builder 抛出错误,指出无法找到 Immutable 类型。
我已经详尽地搜索了针对 MapStruct 和 Immutables 记录的问题,但未能找到解决方案。不幸的是,很少有例子或人们使用 MapStruct 和 Immutables 的组合。 mapstruct-examples 存储库也没有使用不可变对象的示例。
我什至尝试为每个 DtTO(如 UserStatusMapper)定义单独的 Mapper 接口。我只是让它变得更复杂,错误更多。
我创建了一个示例 spring 项目来演示该问题。
GitHub Repo Link。这个演示应用程序与我正在创建的 REST 服务几乎相同。所有数据库(spring-data-jpa,hibernate)的东西都被删除了,我正在使用模拟数据。
如果您签出项目和 运行 演示应用程序,您可以进行两次 API 调用。
获取用户:
要求:
http://localhost:8080/user/api/v1/users/1
回应:
{
"id": 0,
"username": "TestUser",
"email": "TestUser@demo.com",
"userStatus": {
"id": 1,
"status": 1,
"statusName": "Active"
}
创建用户:这里有问题
http://localhost:8080/user/api/v1/users/create
示例输入:
{
"username": "TestUser",
"email": "TestUser@demo.com",
"userStatus": {
"id": 1,
"status": 1,
"statusName": "Active"
}
}
回复:
{
"timestamp": "2019-04-28T09:29:24.933+0000",
"status": 500,
"error": "Internal Server Error",
"message": "Type definition error: [simple type, class com.immutablesmapstruct.demo.dto.model.ImmutableUserDto$Builder]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.immutablesmapstruct.demo.dto.model.ImmutableUserDto$Builder`, problem: Cannot build UserDto, some of required attributes are not set [username, email, userStatus]\n at [Source: (PushbackInputStream); line: 9, column: 1]",
"path": "/user/api/v1/users/create"
}
以下是与问题相关的重要代码片段:
道:
1。 UserDao
public class User {
// Primary Key. Something that is annotated with @Id
private int id;
private String username;
private String email;
private UserStatus userStatus;
private User(Builder builder) {
id = builder.id;
username = builder.username;
email = builder.email;
userStatus = builder.userStatus;
}
public static Builder builder() {
return new Builder();
}
public int getId() {
return id;
}
public String getUsername() {
return username;
}
public String getEmail() {
return email;
}
public UserStatus getUserStatus() {
return userStatus;
}
public static final class Builder {
private int id;
private String username;
private String email;
private UserStatus userStatus;
private Builder() {
}
public Builder setId(int id) {
this.id = id;
return this;
}
public Builder setUsername(String username) {
this.username = username;
return this;
}
public Builder setEmail(String email) {
this.email = email;
return this;
}
public Builder setUserStatus(UserStatus userStatus) {
this.userStatus = userStatus;
return this;
}
public User build() {
return new User(this);
}
2。 UserStatusDao:
package com.immutablesmapstruct.demo.dao.model;
/**
* Status of user.
* Example: Active or Inactive
*/
public class UserStatus {
// Primary Key. Something that is annotated with @Id
private int id;
// A value of 1 or 0
private int status;
// Active , InActive
private String statusName;
private UserStatus(Builder builder) {
id = builder.id;
status = builder.status;
statusName = builder.statusName;
}
public static Builder builder() {
return new Builder();
}
public int getId() {
return id;
}
public int getStatus() {
return status;
}
public String getStatusName() {
return statusName;
}
public static final class Builder {
private int id;
private int status;
private String statusName;
private Builder() {
}
public Builder setId(int id) {
this.id = id;
return this;
}
public Builder setStatus(int status) {
this.status = status;
return this;
}
public Builder setStatusName(String statusName) {
this.statusName = statusName;
return this;
}
public UserStatus build() {
return new UserStatus(this);
}
}
}
DTO
1。 UserDto:
package com.immutablesmapstruct.demo.dto.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;
@Value.Immutable
@Value.Style(defaults = @Value.Immutable(copy = false), init = "set*")
@JsonSerialize(as = ImmutableUserDto.class)
@JsonDeserialize(builder = ImmutableUserDto.Builder.class)
public abstract class UserDto {
@Value.Default
@JsonProperty
public int id() {
return 0;
}
@JsonProperty
public abstract String username();
@JsonProperty
public abstract String email();
@JsonProperty
public abstract UserStatusDto userStatus();
2。 UserStatusDto:
package com.immutablesmapstruct.demo.dto.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;
@Value.Immutable
@Value.Style(defaults = @Value.Immutable(copy = false), init = "set*")
@JsonSerialize(as = ImmutableUserStatusDto.class)
@JsonDeserialize(builder = ImmutableUserStatusDto.Builder.class)
public abstract class UserStatusDto {
@JsonProperty
public abstract int id();
@JsonProperty
public abstract int status();
@JsonProperty
public abstract String statusName();
}
MapStruct UserMapper:
package com.immutablesmapstruct.demo.dto.mapper;
import com.immutablesmapstruct.demo.dao.model.User;
import com.immutablesmapstruct.demo.dao.model.UserStatus;
import com.immutablesmapstruct.demo.dto.model.UserDto;
import com.immutablesmapstruct.demo.dto.model.UserStatusDto;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper(componentModel = "spring")
public interface UserMapper {
UserMapper USER_MAPPER_INSTANCE = Mappers.getMapper(UserMapper.class);
UserDto userDaoToDto(User user);
//Problem here.
User userDtoToDao(UserDto userDto);
UserStatusDto userStatusDaoToDto(UserStatus userStatusDao);
UserStatus userStatusDtoToDao(UserStatusDto userStatusDto);
}
如果我查看 MapStruct 为 userDtoToDao
生成的具体方法,我可以清楚地看到设置器未被识别。
package com.immutablesmapstruct.demo.dto.mapper;
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2019-04-28T02:29:03-0700",
comments = "version: 1.3.0.Final, compiler: javac, environment: Java 1.8.0_191 (Oracle Corporation)"
)
@Component
public class UserMapperImpl implements UserMapper {
...
...
@Override
public User userDtoToDao(UserDto userDto) {
if ( userDto == null ) {
return null;
}
com.immutablesmapstruct.demo.dao.model.User.Builder user = User.builder();
return user.build();
}
....
....
}
Mapstruct 无法识别 UserDto
和 UserStatusDto
中的 getter。
当您将这些抽象 类 中的现有方法(如 public abstract String username()
)更改为像
这样的经典吸气剂时
@JsonProperty("username")
public abstract String getUsername();
MapperImpl
将包含所需的调用。请注意,@JsonProperty
之后需要属性名称本身(因为更改了方法名称)。
以下是完整的 类 UserDto
和 UserStatusDto
,其中包含上述更改:
package com.immutablesmapstruct.demo.dto.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;
@Value.Immutable
@Value.Style(defaults = @Value.Immutable(copy = false), init = "set*")
@JsonSerialize(as = ImmutableUserDto.class)
@JsonDeserialize(builder = ImmutableUserDto.Builder.class)
public abstract class UserDto {
@Value.Default
@JsonProperty("id")
public int getId() {
return 0;
}
@JsonProperty("username")
public abstract String getUsername();
@JsonProperty("email")
public abstract String getEmail();
@JsonProperty("userStatus")
public abstract UserStatusDto getUserStatus();
}
package com.immutablesmapstruct.demo.dto.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;
@Value.Immutable
@Value.Style(defaults = @Value.Immutable(copy = false), init = "set*")
@JsonSerialize(as = ImmutableUserStatusDto.class)
@JsonDeserialize(builder = ImmutableUserStatusDto.Builder.class)
public abstract class UserStatusDto {
@JsonProperty("id")
public abstract int getId();
@JsonProperty("status")
public abstract int getStatus();
@JsonProperty("statusName")
public abstract String getStatusName();
}
我正在使用 spring 构建一个简单的 REST 服务。我将我的实体与 DTO 分开,并使用 Immutables. I needed mapping between DTOs and DAOs, so I chose MapStruct 使 DTO 不可变。 Mapper 无法检测到我在 DAO 中定义的设置器。
问题与
我尝试了@tobias-schulte 提供的
我已经详尽地搜索了针对 MapStruct 和 Immutables 记录的问题,但未能找到解决方案。不幸的是,很少有例子或人们使用 MapStruct 和 Immutables 的组合。 mapstruct-examples 存储库也没有使用不可变对象的示例。
我什至尝试为每个 DtTO(如 UserStatusMapper)定义单独的 Mapper 接口。我只是让它变得更复杂,错误更多。
我创建了一个示例 spring 项目来演示该问题。 GitHub Repo Link。这个演示应用程序与我正在创建的 REST 服务几乎相同。所有数据库(spring-data-jpa,hibernate)的东西都被删除了,我正在使用模拟数据。 如果您签出项目和 运行 演示应用程序,您可以进行两次 API 调用。
获取用户: 要求: http://localhost:8080/user/api/v1/users/1 回应:
{
"id": 0,
"username": "TestUser",
"email": "TestUser@demo.com",
"userStatus": {
"id": 1,
"status": 1,
"statusName": "Active"
}
创建用户:这里有问题 http://localhost:8080/user/api/v1/users/create 示例输入:
{
"username": "TestUser",
"email": "TestUser@demo.com",
"userStatus": {
"id": 1,
"status": 1,
"statusName": "Active"
}
}
回复:
{
"timestamp": "2019-04-28T09:29:24.933+0000",
"status": 500,
"error": "Internal Server Error",
"message": "Type definition error: [simple type, class com.immutablesmapstruct.demo.dto.model.ImmutableUserDto$Builder]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.immutablesmapstruct.demo.dto.model.ImmutableUserDto$Builder`, problem: Cannot build UserDto, some of required attributes are not set [username, email, userStatus]\n at [Source: (PushbackInputStream); line: 9, column: 1]",
"path": "/user/api/v1/users/create"
}
以下是与问题相关的重要代码片段:
道: 1。 UserDao
public class User {
// Primary Key. Something that is annotated with @Id
private int id;
private String username;
private String email;
private UserStatus userStatus;
private User(Builder builder) {
id = builder.id;
username = builder.username;
email = builder.email;
userStatus = builder.userStatus;
}
public static Builder builder() {
return new Builder();
}
public int getId() {
return id;
}
public String getUsername() {
return username;
}
public String getEmail() {
return email;
}
public UserStatus getUserStatus() {
return userStatus;
}
public static final class Builder {
private int id;
private String username;
private String email;
private UserStatus userStatus;
private Builder() {
}
public Builder setId(int id) {
this.id = id;
return this;
}
public Builder setUsername(String username) {
this.username = username;
return this;
}
public Builder setEmail(String email) {
this.email = email;
return this;
}
public Builder setUserStatus(UserStatus userStatus) {
this.userStatus = userStatus;
return this;
}
public User build() {
return new User(this);
}
2。 UserStatusDao:
package com.immutablesmapstruct.demo.dao.model;
/**
* Status of user.
* Example: Active or Inactive
*/
public class UserStatus {
// Primary Key. Something that is annotated with @Id
private int id;
// A value of 1 or 0
private int status;
// Active , InActive
private String statusName;
private UserStatus(Builder builder) {
id = builder.id;
status = builder.status;
statusName = builder.statusName;
}
public static Builder builder() {
return new Builder();
}
public int getId() {
return id;
}
public int getStatus() {
return status;
}
public String getStatusName() {
return statusName;
}
public static final class Builder {
private int id;
private int status;
private String statusName;
private Builder() {
}
public Builder setId(int id) {
this.id = id;
return this;
}
public Builder setStatus(int status) {
this.status = status;
return this;
}
public Builder setStatusName(String statusName) {
this.statusName = statusName;
return this;
}
public UserStatus build() {
return new UserStatus(this);
}
}
}
DTO 1。 UserDto:
package com.immutablesmapstruct.demo.dto.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;
@Value.Immutable
@Value.Style(defaults = @Value.Immutable(copy = false), init = "set*")
@JsonSerialize(as = ImmutableUserDto.class)
@JsonDeserialize(builder = ImmutableUserDto.Builder.class)
public abstract class UserDto {
@Value.Default
@JsonProperty
public int id() {
return 0;
}
@JsonProperty
public abstract String username();
@JsonProperty
public abstract String email();
@JsonProperty
public abstract UserStatusDto userStatus();
2。 UserStatusDto:
package com.immutablesmapstruct.demo.dto.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;
@Value.Immutable
@Value.Style(defaults = @Value.Immutable(copy = false), init = "set*")
@JsonSerialize(as = ImmutableUserStatusDto.class)
@JsonDeserialize(builder = ImmutableUserStatusDto.Builder.class)
public abstract class UserStatusDto {
@JsonProperty
public abstract int id();
@JsonProperty
public abstract int status();
@JsonProperty
public abstract String statusName();
}
MapStruct UserMapper:
package com.immutablesmapstruct.demo.dto.mapper;
import com.immutablesmapstruct.demo.dao.model.User;
import com.immutablesmapstruct.demo.dao.model.UserStatus;
import com.immutablesmapstruct.demo.dto.model.UserDto;
import com.immutablesmapstruct.demo.dto.model.UserStatusDto;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper(componentModel = "spring")
public interface UserMapper {
UserMapper USER_MAPPER_INSTANCE = Mappers.getMapper(UserMapper.class);
UserDto userDaoToDto(User user);
//Problem here.
User userDtoToDao(UserDto userDto);
UserStatusDto userStatusDaoToDto(UserStatus userStatusDao);
UserStatus userStatusDtoToDao(UserStatusDto userStatusDto);
}
如果我查看 MapStruct 为 userDtoToDao
生成的具体方法,我可以清楚地看到设置器未被识别。
package com.immutablesmapstruct.demo.dto.mapper;
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2019-04-28T02:29:03-0700",
comments = "version: 1.3.0.Final, compiler: javac, environment: Java 1.8.0_191 (Oracle Corporation)"
)
@Component
public class UserMapperImpl implements UserMapper {
...
...
@Override
public User userDtoToDao(UserDto userDto) {
if ( userDto == null ) {
return null;
}
com.immutablesmapstruct.demo.dao.model.User.Builder user = User.builder();
return user.build();
}
....
....
}
Mapstruct 无法识别 UserDto
和 UserStatusDto
中的 getter。
当您将这些抽象 类 中的现有方法(如 public abstract String username()
)更改为像
@JsonProperty("username")
public abstract String getUsername();
MapperImpl
将包含所需的调用。请注意,@JsonProperty
之后需要属性名称本身(因为更改了方法名称)。
以下是完整的 类 UserDto
和 UserStatusDto
,其中包含上述更改:
package com.immutablesmapstruct.demo.dto.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;
@Value.Immutable
@Value.Style(defaults = @Value.Immutable(copy = false), init = "set*")
@JsonSerialize(as = ImmutableUserDto.class)
@JsonDeserialize(builder = ImmutableUserDto.Builder.class)
public abstract class UserDto {
@Value.Default
@JsonProperty("id")
public int getId() {
return 0;
}
@JsonProperty("username")
public abstract String getUsername();
@JsonProperty("email")
public abstract String getEmail();
@JsonProperty("userStatus")
public abstract UserStatusDto getUserStatus();
}
package com.immutablesmapstruct.demo.dto.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;
@Value.Immutable
@Value.Style(defaults = @Value.Immutable(copy = false), init = "set*")
@JsonSerialize(as = ImmutableUserStatusDto.class)
@JsonDeserialize(builder = ImmutableUserStatusDto.Builder.class)
public abstract class UserStatusDto {
@JsonProperty("id")
public abstract int getId();
@JsonProperty("status")
public abstract int getStatus();
@JsonProperty("statusName")
public abstract String getStatusName();
}