Задать вопрос
@duds

Mapstruct Mapper выдаёт NullPointerException Cannot invoke because Mapper is null. Как исправить ошибку?

Я не понимаю, почему мой DateMapper не работает.

мои Mapper'ы:

@Mapper(componentModel = MappingConstants.ComponentModel.SPRING,
        uses = {ProductMapper.class, TagMapper.class})
public interface DateMapper {
    DateMapper INSTANCE = Mappers.getMapper(DateMapper.class);

    @Named("mapStringToLocalDateTime")
    default LocalDateTime mapStringToLocalDateTime(String date) {
        return LocalDateTime.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
    }
}


@Mapper(componentModel = MappingConstants.ComponentModel.SPRING,
        uses = {TagMapper.class, DateMapper.class})
public interface ProductMapper {
    ProductMapper INSTANCE = Mappers.getMapper(ProductMapper.class);

    @Mapping(target = "tags", source = "tagDTOs", qualifiedByName = "tagDTOsToTagSet")
    @Mapping(target = "dateOfCreated", source = "stringDate", dateFormat = "yyyy-MM-dd HH:mm", qualifiedByName = "mapStringToLocalDateTime")
    Product productDTOtoProduct(ProductDTO productDTO);

    @Mapping(target = "tagDTOs", source = "tags", qualifiedByName = "TagSetToTagDTOs")
    @Mapping(target = "stringDate", source = "dateOfCreated", dateFormat = "yyyy-MM-dd HH:mm", qualifiedByName = "mapStringToLocalDateTime")
    ProductDTO productToProductDTO(Product product);

    @Named("tagDTOsToTagSet")
    default Set<Tag> tagDTOsToTagSet(TagDTO[] tagDTOs) {
/// logic ///
    }

    @Named("TagSetToTagDTOs")
    default TagDTO[] TagSetTotagDTOs(Set<Tag> tagSet) {
/// logic ///
    }
}


@Mapper(componentModel = MappingConstants.ComponentModel.SPRING,
        uses = {ProductMapper.class, DateMapper.class})
public interface TagMapper {
    TagMapper INSTANCE = Mappers.getMapper(TagMapper.class);

    @Mapping(target = "products", source = "productTitles", qualifiedByName = "productSetToProductTitles")
    @Mapping(target = "dateOfCreated", source = "stringDate", dateFormat = "yyyy-MM-dd HH:mm", qualifiedByName = "mapStringToLocalDateTime")
    Tag tagDTOtoTag(TagDTO tagDTO);

    @Mapping(target = "productTitles", source = "products", qualifiedByName = "ProductTitlesToProductSet")
    @Mapping(target = "stringDate", source = "dateOfCreated", dateFormat = "yyyy-MM-dd HH:mm", qualifiedByName = "mapStringToLocalDateTime")
    TagDTO tagToTagDTO(Tag tag);

    @Named("productSetToProductTitles")
    default String[] productSetToProductTitles(Set<Product> products) {
        /// logic ///
    }

    @Named("ProductTitlesToProductSet")
    default Set<Product> ProductTitlesToProductSet(String[] productTitles) {
        /// logic ///
    }
}


мои DTO:

@Setter
@Getter
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ProductDTO {
    private Long id;
    private TagDTO[] tagDTOs;
    private Double price;
    private String stringDate;
    private String title;
    private String description;
    private String city;
    private int amount;
}


@Setter
@Getter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TagDTO {
    Long id;
    String name;
    String[] productTitles;
    String stringDate;

    public TagDTO(String name) {
        this.name = name;
    }

    public TagDTO(Long id) {
        this.id = id;
    }
}


Мои POJO:

Product:
@Entity
@Table(name = "products")
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Builder
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
    private String description;
    private Double price;
    private String city;
    private int amount = 1;
    @ManyToMany(mappedBy = "products")
    private Set<Tag> tags = new HashSet<>();
    private LocalDateTime dateOfCreated;

    public Product(String title) {
        this.title = title;
    }

    @PrePersist
    private void onCreate() { dateOfCreated = LocalDateTime.now(); }

/// custom logic ///

}


Tag:

@Entity
@Table(name = "tags")
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Tag {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    @ManyToMany(cascade = CascadeType.REFRESH, fetch = FetchType.LAZY)
    @JoinTable(
            name = "tags_Products",
            joinColumns = @JoinColumn(name = "Tag_id"),
            inverseJoinColumns = @JoinColumn(name = "product_id"))
    private Set<Product> products = new HashSet<>();
    private LocalDateTime dateOfCreated;

    @PrePersist
    private void onCreate() {
        dateOfCreated = LocalDateTime.now();
    }

/// custom logic ///

}


мой pom.xml:

<properties>
		<java.version>24</java.version>
		<lombok.version>1.18.38</lombok.version>
		<mapstruct.version>1.6.3</mapstruct.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.mapstruct</groupId>
			<artifactId>mapstruct-processor</artifactId>
			<version>${mapstruct.version}</version>
		</dependency>
		<dependency>
			<groupId>org.mapstruct</groupId>
			<artifactId>mapstruct</artifactId>
			<version>${mapstruct.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-rest</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.datatype</groupId>
			<artifactId>jackson-datatype-jsr310</artifactId>
			<version>2.18.2</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.18.2</version>
		</dependency>

		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>${lombok.version}</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>jakarta.validation</groupId>
			<artifactId>jakarta.validation-api</artifactId>
			<version>3.1.0</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
			<version>3.4.0</version>
		</dependency>
        <dependency>
            <groupId>org.jetbrains</groupId>
            <artifactId>annotations</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<annotationProcessorPaths>
						<path>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
							<version>${lombok.version}</version>
						</path>
					</annotationProcessorPaths>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.11.0</version>
				<configuration>
					<annotationProcessorPaths>
						<path>
							<groupId>org.mapstruct</groupId>
							<artifactId>mapstruct-processor</artifactId>
							<version>${mapstruct.version}</version>
						</path>
					</annotationProcessorPaths>
				</configuration>
			</plugin>
		</plugins>
	</build>


у сгенерированного mapstruct'ом MapperImpl есть @Autowired DateMapper:

@Component
public class TagMapperImpl implements TagMapper {
    @Autowired
    private DateMapper dateMapper;
/// logic ///
}

@Component
public class ProductMapperImpl implements ProductMapper {
    @Autowired
    private DateMapper dateMapper;
/// logic ///
}


у сгенерированного mapstruct'ом DateMapperImpl есть аннотация @Component:

@Component
public class DateMapperImpl implements DateMapper {
    public DateMapperImpl() {
        super();
    }
}
  • Вопрос задан
  • 57 просмотров
Подписаться 1 Простой 6 комментариев
Пригласить эксперта
Ответы на вопрос 1
xez
@xez Куратор тега Java
TL Junior Roo
Я просто не понимаю, почему может возникать NPO

(Видимо, имеется ввиду NPE)

NullPointerException может возникать потому, что аннтоация @Autowired не гарантирует внедрение зависимости.
Погуглите "autowired bad practice"
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы