大家好,这是我的项目:
两个实体通过某种@OneToMany
关系相互联系:
@Entity
public class Brand {
@Id
@GeneratedValue
private Long id;
@Column
@NotNull(message = "Brand can not have empty name.")
private String name;
@Column
private String description;
@OneToMany(mappedBy="brand"
, cascade= {CascadeType.DETACH,
CascadeType.MERGE,
CascadeType.PERSIST,
CascadeType.REFRESH},
fetch = FetchType.EAGER)
@OrderBy("price ASC") // order products by price
private List<Product> productList;
// getters and setter following here ...
}
@Entity
public class Product {
@Id
@GeneratedValue
private Long id;
@Column
@NotNull(message = "Product can not have empty name.")
private String name;
@Column
private Double price;
@Column
private Boolean onSale=false;
@ManyToOne(cascade= {CascadeType.DETACH,
CascadeType.MERGE,
CascadeType.PERSIST,
CascadeType.REFRESH})
@JoinColumn(name="brand_id", nullable=false)
private Brand brand;
// getters and setter following here ...
}
package com.microservices.product.datatranferobject;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ProductDTO {
private Long id;
private String name;
private Double price;
@JsonIgnore // omit this property when exposing data over the API
private Boolean onSale;
private String event;
public ProductDTO() {
}
public ProductDTO(Long id, String name, Double price, String event, Boolean onSale) {
super();
this.id = id;
this.name = name;
this.price = price;
this.event = event;
this.onSale=onSale;
}
public Boolean getOnSale() {
return onSale;
}
public void setOnSale(Boolean onSale) {
this.onSale = onSale;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String getEvent() {
return onSale?"ON SALE":null;
}
public void setEvent(String event) {
this.event = event;
}
}
public class BrandDTO {
private String name;
private List<ProductDTO> productList;
public BrandDTO() {}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<ProductDTO> getProductList() {
return productList;
}
public void setProductList(List<ProductDTO> productList) {
this.productList = productList;
}
}
一个简单的DAO类:
public interface BrandRepository extends JpaRepository<Brand, Long>{
List<Brand> findAllByOrderByName();
}
一个简单的服务:
public interface BrandService {
List<Brand> getAllBrands();
}
@Service
public class BrandServiceImpl implements BrandService {
@Autowired
BrandRepository myBrandRepo;
@Override
public List<Brand> getAllBrands(){
return myBrandRepo.findAllByOrderByName();
}
}
和一个控制器,该控制器使用我自定义的编程Mapper将产品映射到ProductDTO:
public class ModelMapper {
public static BrandDTO makeBrandDTO(Brand myBrand)
{
BrandDTO myBrandDTO=new BrandDTO();
org.modelmapper.ModelMapper myStandardMapper=new org.modelmapper.ModelMapper();
List<ProductDTO> myProductsList=myBrand.getProductList()
.stream()
.map(product->myStandardMapper.map(product, ProductDTO.class))
.collect(Collectors.toList());
myBrandDTO.setProductList(myProductsList);
myBrandDTO.setName(myBrand.getName());
return myBrandDTO;
}
}
@RestController
@RequestMapping("v1/search")
public class BrandController {
@Autowired
BrandService myBrandService;
@GetMapping("/get/products/")
public Map<String, List<ProductDTO>> getAllProductsMap(){
List<BrandDTO> myList= myBrandService.getAllBrands()
.stream().map(brand->ModelMapper.makeBrandDTO(brand))
.collect(Collectors.toList());
Map<String, List<ProductDTO>> myMap=new TreeMap<String, List<ProductDTO>> ();
myList.forEach(brand->myMap.put(brand.getName(), brand.getProductList()));
return myMap;
}
}
ProductDTO与Product实体完全相同,因此我将节省时间并写下来。
因此,问题来了。我正在使用Junit来测试我的Controller,并让以下类运行测试:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ProductApplication.class,webEnvironment=WebEnvironment.RANDOM_PORT)
public class ControllerLayerTester {
private static Log myLogger = LogFactory.getLog(ControllerLayerTester.class);
private static RestTemplate restTemplate;
private static HttpHeaders headers;
@LocalServerPort
private int port;
@BeforeClass
public static void runBeforeAllTestMethods() {
restTemplate = new RestTemplate();
headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
}
/**
* simple test to verify the given requirements
*/
@Test
public void testBrandListIsOrdered() {
TreeMap<String, List<ProductDTO>> productList=restTemplate.getForObject("http://localhost:"+port+"/v1/search/get/products/",TreeMap.class);
for (List<ProductDTO> myProductList:productList.values()) {
myProductList.forEach(product->assertTrue(product.getId()!=null));
}
}
}
当我运行它时,出现以下错误:
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.microservices.product.datatranferobject.ProductDTO
at java.util.ArrayList.forEach(ArrayList.java:1257)
at com.microservices.product.ControllerLayerTester.testBrandListIsOrdered(ControllerLayerTester.java:81)
我在这里做错什么了吗?为什么不让列表填充我的实体,而是填充LinkedHashMaps?是否有解决方案以获得产品列表?
编辑:
我还在这里提供我的项目依赖关系,我在帖子的顶部还添加了DTO:
buildscript {
ext {
springBootVersion = '2.1.0.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'com.microservices'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
implementation('org.springframework.boot:spring-boot-starter-data-jpa')
implementation('org.springframework.boot:spring-boot-starter-web')
compile("org.springframework.boot:spring-boot-devtools")
compile group: 'org.modelmapper', name: 'modelmapper', version: '2.1.0'
runtimeOnly('com.h2database:h2')
testImplementation('org.springframework.boot:spring-boot-starter-test')
testImplementation 'org.assertj:assertj-core:3.15.0'
compile group: 'com.google.guava', name: 'guava', version: '23.5-jre'
compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.7.0'
compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.7.0'
}
问题来源:Stack Overflow
问题是TreeMap<String, List<ProductDTO>>
无法从TreeMap.class
内部推断参数化restTemplate.getForObject(...)
您将要使用更通用的版本:
restTemplate.exchange(
"http://localhost:"+port+"/v1/search/get/products/",
HttpMethod.GET,
new HttpEntity<>(null, headers),
new ParameterizedTypeReference<TreeMap<String, List<ProductDTO>>() {}
)
回答来源:Stack Overflow
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。