ard-admin/src/main/java/com/ard/web/controller/sample/AnnotationController.java
New file @@ -0,0 +1,197 @@ package com.ard.web.controller.sample; import com.ard.sample.annotation.model.dto.AnnotationDTO; import com.ard.sample.annotation.model.dto.AnnotationDirectoryDTO; import com.ard.sample.annotation.model.entity.AnnotationDirectoryEntity; import com.ard.sample.annotation.model.entity.AnnotationEntity; import com.ard.sample.annotation.service.IAnnotationDirectoryService; import com.ard.sample.annotation.service.IAnnotationService; import com.ard.sample.annotation.util.ConvertUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.List; import java.util.Map; @Api(tags = "标注管理") @Slf4j @RestController @RequestMapping("/annotation") @RequiredArgsConstructor public class AnnotationController { private final IAnnotationDirectoryService directoryService; private final IAnnotationService annotationService; // ====================== 目录接口 ====================== @ApiOperation("新增目录") @PostMapping("/directory") public ResponseEntity<Map<String, Object>> addDirectory(@RequestBody AnnotationDirectoryEntity entity) { Map<String, Object> result = new HashMap<>(); try { //AnnotationDirectoryEntity entity = ConvertUtil.directoryDtoToEntity(dto); boolean success = directoryService.addDirectory(entity); result.put("success", success); result.put("msg", success ? "目录新增成功" : "目录新增失败"); result.put("data", entity.getId()); // 返回新增ID } catch (Exception e) { log.error("新增目录异常", e); result.put("success", false); result.put("msg", "新增目录失败:" + e.getMessage()); } return ResponseEntity.ok(result); } @ApiOperation("修改目录") @PutMapping("/directory") public ResponseEntity<Map<String, Object>> editDirectory(@RequestBody AnnotationDirectoryEntity entity) { Map<String, Object> result = new HashMap<>(); try { // AnnotationDirectoryEntity entity = ConvertUtil.directoryDtoToEntity(dto); boolean success = directoryService.editDirectory(entity); result.put("success", success); result.put("msg", success ? "目录修改成功" : "目录修改失败"); } catch (Exception e) { log.error("修改目录异常", e); result.put("success", false); result.put("msg", "修改目录失败:" + e.getMessage()); } return ResponseEntity.ok(result); } @ApiOperation("删除目录及子项") @DeleteMapping("/directory/{id}") public ResponseEntity<Map<String, Object>> deleteDirectory(@PathVariable Integer id) { Map<String, Object> result = new HashMap<>(); try { boolean success = directoryService.deleteDirectory(id); result.put("success", success); result.put("msg", success ? "目录删除成功" : "目录删除失败"); } catch (Exception e) { log.error("删除目录异常", e); result.put("success", false); result.put("msg", "删除目录失败:" + e.getMessage()); } return ResponseEntity.ok(result); } // ====================== 标记接口 ====================== @ApiOperation("新增标记") @PostMapping public ResponseEntity<Map<String, Object>> addAnnotation(@RequestBody AnnotationDTO dto) { Map<String, Object> result = new HashMap<>(); try { AnnotationEntity entity = ConvertUtil.annotationDtoToEntity(dto); boolean success = annotationService.addAnnotation(entity); result.put("success", success); result.put("msg", success ? "标记新增成功" : "标记新增失败"); result.put("data", entity.getId()); } catch (Exception e) { log.error("新增标记异常", e); result.put("success", false); result.put("msg", "新增标记失败:" + e.getMessage()); } return ResponseEntity.ok(result); } @ApiOperation("修改标记") @PutMapping public ResponseEntity<Map<String, Object>> editAnnotation(@RequestBody AnnotationDTO dto) { Map<String, Object> result = new HashMap<>(); try { AnnotationEntity entity = ConvertUtil.annotationDtoToEntity(dto); boolean success = annotationService.editAnnotation(entity); result.put("success", success); result.put("msg", success ? "标记修改成功" : "标记修改失败"); } catch (Exception e) { log.error("修改标记异常", e); result.put("success", false); result.put("msg", "修改标记失败:" + e.getMessage()); } return ResponseEntity.ok(result); } @ApiOperation("删除标记") @DeleteMapping("/{id}") public ResponseEntity<Map<String, Object>> deleteAnnotation(@PathVariable Integer id) { Map<String, Object> result = new HashMap<>(); try { boolean success = annotationService.deleteAnnotation(id); result.put("success", success); result.put("msg", success ? "标记删除成功" : "标记删除失败"); } catch (Exception e) { log.error("删除标记异常", e); result.put("success", false); result.put("msg", "删除标记失败:" + e.getMessage()); } return ResponseEntity.ok(result); } @ApiOperation("批量删除标记") @DeleteMapping("/batch") public ResponseEntity<Map<String, Object>> batchDeleteAnnotation(@RequestBody List<Integer> ids) { Map<String, Object> result = new HashMap<>(); try { boolean success = annotationService.batchDeleteAnnotation(ids); result.put("success", success); result.put("msg", success ? "标记批量删除成功" : "标记批量删除失败"); } catch (Exception e) { log.error("批量删除标记异常", e); result.put("success", false); result.put("msg", "批量删除标记失败:" + e.getMessage()); } return ResponseEntity.ok(result); } // 层级查询:目录→标记→坐标 @ApiOperation("按目标id获取所有目录及子标记信息") @GetMapping("/directory/{directoryId}") public ResponseEntity<Map<String, Object>> getDirectoryWithAnnotations(@PathVariable Integer directoryId) { Map<String, Object> result = new HashMap<>(); try { // 1. 查询目录 AnnotationDirectoryEntity dirEntity = directoryService.getById(directoryId); if (dirEntity == null) { result.put("success", false); result.put("msg", "目录不存在"); return ResponseEntity.ok(result); } AnnotationDirectoryDTO dirDto = ConvertUtil.directoryEntityToDto(dirEntity); // 2. 查询目录下标记 List<AnnotationEntity> annoEntities = annotationService.listByDirectoryId(directoryId); List<AnnotationDTO> annoDtos = ConvertUtil.annotationEntityListToDtoList(annoEntities); dirDto.setAnnotations(annoDtos); result.put("success", true); result.put("data", dirDto); } catch (Exception e) { log.error("查询目录及标记异常", e); result.put("success", false); result.put("msg", "查询失败:" + e.getMessage()); } return ResponseEntity.ok(result); } /** * 新增:获取全部目录及下属标注数据 */ @ApiOperation("获取全部目录及下属标注数据") @GetMapping("/directory/all") public ResponseEntity<Map<String, Object>> listAllDirectoryWithAnnotations() { List<AnnotationDirectoryDTO> directoryList = directoryService.listAllDirectoryWithAnnotations(); Map<String, Object> result = new HashMap<>(); result.put("success", true); result.put("msg", "查询全部目录及标注成功"); result.put("data", directoryList); return ResponseEntity.ok(result); } } ard-sample/src/main/java/com/ard/sample/annotation/mapper/AnnotationDirectoryMapper.java
New file @@ -0,0 +1,9 @@ package com.ard.sample.annotation.mapper; import com.ard.sample.annotation.model.entity.AnnotationDirectoryEntity; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; @Mapper public interface AnnotationDirectoryMapper extends BaseMapper<AnnotationDirectoryEntity> { } ard-sample/src/main/java/com/ard/sample/annotation/mapper/AnnotationMapper.java
New file @@ -0,0 +1,14 @@ package com.ard.sample.annotation.mapper; import com.ard.sample.annotation.model.entity.AnnotationEntity; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import java.util.List; @Mapper public interface AnnotationMapper extends BaseMapper<AnnotationEntity> { // 按目录ID查询标记列表 List<AnnotationEntity> selectByDirectoryId(@Param("directoryId") Integer directoryId); } ard-sample/src/main/java/com/ard/sample/annotation/model/dto/AnnotationDTO.java
New file @@ -0,0 +1,37 @@ package com.ard.sample.annotation.model.dto; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; @Data @AllArgsConstructor @NoArgsConstructor @Builder public class AnnotationDTO { private Integer id; private Integer directoryId; private String name; private String color; private String annotationType; private List<AnnotationPointsDTO> coordinateInfo; private String imageUrl; private String drawer; private String description; private Long createTime; private Long updateTime; } ard-sample/src/main/java/com/ard/sample/annotation/model/dto/AnnotationDirectoryDTO.java
New file @@ -0,0 +1,31 @@ package com.ard.sample.annotation.model.dto; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.TableField; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; /** * 标注目录的DTO类 * */ @Data @AllArgsConstructor @NoArgsConstructor @Builder public class AnnotationDirectoryDTO { private Integer id; private String directoryName; private List<AnnotationDTO> annotations; // 层级返回用 private String directoryRemark; private Long createTime; private Long updateTime; } ard-sample/src/main/java/com/ard/sample/annotation/model/dto/AnnotationPointsDTO.java
New file @@ -0,0 +1,26 @@ package com.ard.sample.annotation.model.dto; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; /** * 点、线、面、圆标注的DTO类 * */ @Data @AllArgsConstructor @NoArgsConstructor @Builder @JsonInclude(JsonInclude.Include.NON_NULL) public class AnnotationPointsDTO { private Double longitude; private Double latitude; private Double height; private Double radius; } ard-sample/src/main/java/com/ard/sample/annotation/model/entity/AnnotationDirectoryEntity.java
New file @@ -0,0 +1,33 @@ package com.ard.sample.annotation.model.entity; import com.baomidou.mybatisplus.annotation.*; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @Data @Builder @NoArgsConstructor @AllArgsConstructor @TableName(value = "annotation_directory") public class AnnotationDirectoryEntity implements Serializable { @TableId(type = IdType.AUTO) private Integer id; @TableField(value = "directory_name") private String directoryName; @TableField(value = "directory_remark") private String directoryRemark; @TableField(value = "create_time", fill = FieldFill.INSERT) private Long createTime; @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE) private Long updateTime; } ard-sample/src/main/java/com/ard/sample/annotation/model/entity/AnnotationEntity.java
New file @@ -0,0 +1,50 @@ package com.ard.sample.annotation.model.entity; import com.baomidou.mybatisplus.annotation.*; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @Data @Builder @NoArgsConstructor @AllArgsConstructor @TableName(value = "annotation") public class AnnotationEntity implements Serializable { @TableId(type = IdType.AUTO) private Integer id; @TableField(value = "directory_id") private Integer directoryId; @TableField(value = "name") private String name; @TableField(value = "color") private String color; @TableField(value = "annotation_type") private String annotationType; @TableField(value = "coordinate_info") private byte[] coordinateInfo; @TableField(value = "image_url") private String imageUrl; @TableField(value = "drawer") private String drawer; @TableField(value = "description") private String description; @TableField(value = "create_time", fill = FieldFill.INSERT) private Long createTime; @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE) private Long updateTime; } ard-sample/src/main/java/com/ard/sample/annotation/service/IAnnotationDirectoryService.java
New file @@ -0,0 +1,19 @@ package com.ard.sample.annotation.service; import com.ard.sample.annotation.model.dto.AnnotationDirectoryDTO; import com.ard.sample.annotation.model.entity.AnnotationDirectoryEntity; import com.baomidou.mybatisplus.extension.service.IService; import java.util.List; public interface IAnnotationDirectoryService extends IService<AnnotationDirectoryEntity> { // 新增目录 boolean addDirectory(AnnotationDirectoryEntity entity); // 修改目录 boolean editDirectory(AnnotationDirectoryEntity entity); // 删除目录(级联删除标记) boolean deleteDirectory(Integer id); // 新增:查询全部目录(含下属标注数据) List<AnnotationDirectoryDTO> listAllDirectoryWithAnnotations(); } ard-sample/src/main/java/com/ard/sample/annotation/service/IAnnotationService.java
New file @@ -0,0 +1,18 @@ package com.ard.sample.annotation.service; import com.ard.sample.annotation.model.entity.AnnotationEntity; import com.baomidou.mybatisplus.extension.service.IService; import java.util.List; public interface IAnnotationService extends IService<AnnotationEntity> { // 新增标记 boolean addAnnotation(AnnotationEntity entity); // 修改标记 boolean editAnnotation(AnnotationEntity entity); // 删除标记 boolean deleteAnnotation(Integer id); // 批量删除标记 boolean batchDeleteAnnotation(List<Integer> ids); // 按目录ID查询标记 List<AnnotationEntity> listByDirectoryId(Integer directoryId); } ard-sample/src/main/java/com/ard/sample/annotation/service/impl/AnnotationDirectoryServiceImpl.java
New file @@ -0,0 +1,147 @@ package com.ard.sample.annotation.service.impl; import com.ard.common.utils.bean.BeanUtils; import com.ard.sample.annotation.mapper.AnnotationMapper; import com.ard.sample.annotation.model.dto.AnnotationDTO; import com.ard.sample.annotation.model.dto.AnnotationDirectoryDTO; import com.ard.sample.annotation.model.entity.AnnotationDirectoryEntity; import com.ard.sample.annotation.model.entity.AnnotationEntity; import com.ard.sample.annotation.service.IAnnotationDirectoryService; import com.ard.sample.annotation.service.IAnnotationService; import com.ard.sample.annotation.util.JsonSerializeUtil; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ard.sample.annotation.mapper.AnnotationDirectoryMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Slf4j @Service @RequiredArgsConstructor public class AnnotationDirectoryServiceImpl extends ServiceImpl<AnnotationDirectoryMapper, AnnotationDirectoryEntity> implements IAnnotationDirectoryService { // 注入已实现的AnnotationService(而非直接用Mapper),复用其查询逻辑 private final IAnnotationService annotationService; private final AnnotationMapper annotationMapper; @Override public boolean addDirectory(AnnotationDirectoryEntity entity) { return save(entity); } @Override public boolean editDirectory(AnnotationDirectoryEntity entity) { if (entity.getId() == null) { log.error("修改目录失败:ID为空"); return false; } return updateById(entity); } @Override @Transactional(rollbackFor = Exception.class) // 事务保证级联删除 public boolean deleteDirectory(Integer id) { if (id == null) { log.error("删除目录失败:ID为空"); return false; } // 1. 删除目录下所有标记 annotationMapper.deleteByMap(Map.of("directory_id", id)); // 2. 删除目录 boolean result = removeById(id); log.info("删除目录{},结果:{}", id, result); return result; } /** * 查询全部目录(含下属标注数据) * 修复点:替换自定义Mapper方法为MyBatis-Plus通用查询,避免SQL映射缺失问题 */ @Override public List<AnnotationDirectoryDTO> listAllDirectoryWithAnnotations() { // 1. 查询所有目录 List<AnnotationDirectoryEntity> directoryEntities = list(); if (directoryEntities.isEmpty()) { return List.of(); } // 2. 批量查询所有标注,按目录ID分组(减少数据库查询次数) List<AnnotationEntity> allAnnotations = annotationService.list(); Map<Integer, List<AnnotationEntity>> annotationMap = allAnnotations.stream() .collect(Collectors.groupingBy(AnnotationEntity::getDirectoryId)); // 3. 遍历目录,组装DTO(关联下属标注) return directoryEntities.stream().map(directoryEntity -> { AnnotationDirectoryDTO directoryDTO = AnnotationDirectoryDTO.builder().build(); BeanUtils.copyProperties(directoryEntity, directoryDTO); // 4. 获取当前目录下的标注(从分组Map中获取,避免循环查库) List<AnnotationEntity> annotationEntities = annotationMap.getOrDefault(directoryEntity.getId(), List.of()); // 5. 标注实体转DTO(反序列化坐标数据) List<AnnotationDTO> annotationDTOList = annotationEntities.stream().map(annotationEntity -> { AnnotationDTO annotationDTO = AnnotationDTO.builder().build(); BeanUtils.copyProperties(annotationEntity, annotationDTO); try { // 反序列化坐标数据 annotationDTO.setCoordinateInfo( JsonSerializeUtil.deserialize(annotationEntity.getCoordinateInfo()) ); } catch (Exception e) { log.error("反序列化标注坐标失败,标注ID:{}", annotationEntity.getId(), e); annotationDTO.setCoordinateInfo(null); } return annotationDTO; }).collect(Collectors.toList()); // 6. 设置目录下的标注列表 directoryDTO.setAnnotations(annotationDTOList); return directoryDTO; }).collect(Collectors.toList()); } // /** // * 查询全部目录(含下属标注数据) // */ // @Override // public List<AnnotationDirectoryDTO> listAllDirectoryWithAnnotations() { // // 1. 查询所有目录 // List<AnnotationDirectoryEntity> directoryEntities = list(); // // // 2. 遍历目录,关联查询标注数据并组装DTO // return directoryEntities.stream().map(directoryEntity -> { // AnnotationDirectoryDTO directoryDTO = AnnotationDirectoryDTO.builder().build(); // BeanUtils.copyProperties(directoryEntity, directoryDTO); // // // 3. 查询当前目录下的所有标注 // List<AnnotationEntity> annotationEntities = annotationMapper.selectByDirectoryId(directoryEntity.getId()); // // // 4. 标注实体转DTO(反序列化坐标数据) // List<AnnotationDTO> annotationDTOList = annotationEntities.stream().map(annotationEntity -> { // AnnotationDTO annotationDTO = AnnotationDTO.builder().build(); // BeanUtils.copyProperties(annotationEntity, annotationDTO); // try { // // 反序列化坐标数据 // annotationDTO.setCoordinateInfo( // JsonSerializeUtil.deserialize(annotationEntity.getCoordinateInfo()) // ); // } catch (Exception e) { // log.error("反序列化标注坐标失败,标注ID:{}", annotationEntity.getId(), e); // annotationDTO.setCoordinateInfo(null); // } // return annotationDTO; // }).collect(Collectors.toList()); // // // 5. 给目录DTO设置下属标注列表(需先给AnnotationDirectoryDTO新增annotations字段) // directoryDTO.setAnnotations(annotationDTOList); // return directoryDTO; // }).collect(Collectors.toList()); // } } ard-sample/src/main/java/com/ard/sample/annotation/service/impl/AnnotationServiceImpl.java
New file @@ -0,0 +1,64 @@ package com.ard.sample.annotation.service.impl; import com.ard.sample.annotation.mapper.AnnotationMapper; import com.ard.sample.annotation.model.entity.AnnotationEntity; import com.ard.sample.annotation.service.IAnnotationService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import java.util.List; @Slf4j @Service @RequiredArgsConstructor public class AnnotationServiceImpl extends ServiceImpl<AnnotationMapper, AnnotationEntity> implements IAnnotationService { @Override public boolean addAnnotation(AnnotationEntity entity) { return save(entity); } @Override public boolean editAnnotation(AnnotationEntity entity) { if (entity.getId() == null) { log.error("修改标记失败:ID为空"); return false; } return updateById(entity); } @Override public boolean deleteAnnotation(Integer id) { if (id == null) { log.error("删除标记失败:ID为空"); return false; } boolean result = removeById(id); log.info("删除标记{},结果:{}", id, result); return result; } @Override public boolean batchDeleteAnnotation(List<Integer> ids) { if (CollectionUtils.isEmpty(ids)) { log.error("批量删除标记失败:ID列表为空"); return false; } boolean result = removeByIds(ids); log.info("批量删除标记{},结果:{}", ids, result); return result; } @Override public List<AnnotationEntity> listByDirectoryId(Integer directoryId) { if (directoryId == null) { log.error("按目录查询标记失败:目录ID为空"); return List.of(); } return lambdaQuery().eq(AnnotationEntity::getDirectoryId, directoryId).list(); } } ard-sample/src/main/java/com/ard/sample/annotation/util/ConvertUtil.java
New file @@ -0,0 +1,57 @@ package com.ard.sample.annotation.util; import com.ard.sample.annotation.model.dto.AnnotationDTO; import com.ard.sample.annotation.model.dto.AnnotationDirectoryDTO; import com.ard.sample.annotation.model.dto.AnnotationPointsDTO; import com.ard.sample.annotation.model.entity.AnnotationDirectoryEntity; import com.ard.sample.annotation.model.entity.AnnotationEntity; import org.springframework.beans.BeanUtils; import java.util.List; import java.util.stream.Collectors; public class ConvertUtil { // 目录DTO → 目录Entity public static AnnotationDirectoryEntity directoryDtoToEntity(AnnotationDirectoryDTO dto) { AnnotationDirectoryEntity entity = new AnnotationDirectoryEntity(); BeanUtils.copyProperties(dto, entity); return entity; } // 目录Entity → 目录DTO public static AnnotationDirectoryDTO directoryEntityToDto(AnnotationDirectoryEntity entity) { AnnotationDirectoryDTO dto = new AnnotationDirectoryDTO(); BeanUtils.copyProperties(entity, dto); return dto; } // 标记DTO → 标记Entity(含坐标序列化) public static AnnotationEntity annotationDtoToEntity(AnnotationDTO dto) throws Exception { AnnotationEntity entity = new AnnotationEntity(); BeanUtils.copyProperties(dto, entity); // 序列化坐标数据 entity.setCoordinateInfo(JsonSerializeUtil.serialize(dto.getCoordinateInfo())); return entity; } // 标记Entity → 标记DTO(含坐标反序列化) public static AnnotationDTO annotationEntityToDto(AnnotationEntity entity) throws Exception { AnnotationDTO dto = new AnnotationDTO(); BeanUtils.copyProperties(entity, dto); // 反序列化坐标数据 List<AnnotationPointsDTO> points = JsonSerializeUtil.deserialize(entity.getCoordinateInfo()); dto.setCoordinateInfo(points); return dto; } // 标记Entity列表 → 标记DTO列表 public static List<AnnotationDTO> annotationEntityListToDtoList(List<AnnotationEntity> entityList) { return entityList.stream().map(entity -> { try { return annotationEntityToDto(entity); } catch (Exception e) { throw new RuntimeException("标记Entity转DTO失败", e); } }).collect(Collectors.toList()); } } ard-sample/src/main/java/com/ard/sample/annotation/util/JsonSerializeUtil.java
New file @@ -0,0 +1,32 @@ package com.ard.sample.annotation.util; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.ard.sample.annotation.model.dto.AnnotationPointsDTO; import org.springframework.stereotype.Component; import java.util.List; @Component public class JsonSerializeUtil { private static final ObjectMapper objectMapper = new ObjectMapper(); // 序列化:List<AnnotationPointsDTO> → byte[] public static byte[] serialize(List<AnnotationPointsDTO> points) throws JsonProcessingException { if (points == null) { return null; } String json = objectMapper.writeValueAsString(points); return json.getBytes(); } // 反序列化:byte[] → List<AnnotationPointsDTO> public static List<AnnotationPointsDTO> deserialize(byte[] bytes) throws JsonProcessingException { if (bytes == null || bytes.length == 0) { return null; } String json = new String(bytes); return objectMapper.readValue(json, objectMapper.getTypeFactory().constructCollectionType(List.class, AnnotationPointsDTO.class)); } }