Spring 休息文档。片段生成时无效的 UTF-8 中间字节
Spring Rest Docs. Invalid UTF-8 middle byte while snippets generation
请帮助我解决我在使用 Spring Rest 文档时遇到的问题。
我已经根据 Spring 手册进行了所有必需的设置。
我写了 Spring MVC 测试。这是代码。奇怪的符号是俄语。
@WebAppConfiguration
@ContextConfiguration(classes = {TestConfiguration.class})
@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles({"test"})
@Slf4j
public class ProductApiControllerTest {
protected static final long TEST_PRODUCT_ID_1 = 11_071_076_993L;
protected static final long TEST_PRODUCT_ID_2 = 21_071_076_994L;
public static final Product TEST_PRODUCT_1 = Product.builder()
.id(TEST_PRODUCT_ID_1)
.productId(TEST_PRODUCT_ID_1)
.name("WRX3000")
.fullName("WRX3000")
.regionPickupAvailable(Arrays.asList("a100"))
.regionDeliveryAvailable(Arrays.asList("b200"))
.categoryId(100500)
.categoryName("Телевизоры")
.categories(Arrays.asList(10L, 20L, 30L))
.brandId(200300)
.brandName("Samsung")
.description("AMOLED HD Телевизор 4 поколения")
.prices(Arrays.asList(Price.builder().baseStore("b200").priceId(777).priceValue(2990d).oldPriceValue(3490d).build()))
.build();
@Mock
private SearchService searchServiceMock;
@InjectMocks
private ProductApiController controller;
private MockMvc mockMvc;
private RestDocumentationResultHandler document;
@Rule
public final RestDocumentation restDocumentation = new RestDocumentation("target/generated-snippets");
@Before
public void init() {
MockitoAnnotations.initMocks(this);
this.document = document("{method-name}", preprocessResponse(prettyPrint()));
mockMvc = MockMvcBuilders.standaloneSetup(controller)
.apply(documentationConfiguration(this.restDocumentation).snippets().withEncoding("UTF-8"))
.alwaysDo(document)
.build();
}
@Test
public void testGetProduct() throws Exception {
log.info("Test getProduct(..) from ProductApiController");
when(searchServiceMock.findByProductId(TEST_PRODUCT_ID_1, "b200")).thenReturn(TEST_PRODUCT_1);
this.document.snippets(responseFields(
fieldWithPath("id").description("Идентификатор для служебных целей поисковой машины."),
fieldWithPath("name").description("Название продукта"),
fieldWithPath("fullName").description("Полное название продукта"),
fieldWithPath("productId").description("Идентификатор (SKU) товара"),
fieldWithPath("regionPickupAvailable").description("Показывает доступен ли продукт для самовывоза в данном регионе"),
fieldWithPath("regionDeliveryAvailable").description("Показывает доступен ли продукт для доставки в данном регионе"),
fieldWithPath("categoryId").description("Идентификатор категории, к которой принадлежит товар"),
fieldWithPath("categoryName").description("Название категории, к которой принадлежит товар"),
fieldWithPath("categories").description("Список идентификаторов категорий к которым принадлежит товар"),
fieldWithPath("brandId").description("Идентификатор бренда товара"),
fieldWithPath("brandName").description("Название бренда продукта"),
fieldWithPath("description").description("Описание товара"),
fieldWithPath("propertyAggregate").description("Какая-то фигня"),
fieldWithPath("propepropertyAggregatertyMap").description("Дополнительные свойства товара"),
fieldWithPath("price").description("Цена товара"),
fieldWithPath("oldPrice").description("Предыдущая цена товара")
));
mockMvc.perform(get(Constants.RestApiV1.ROOT_PATH + "/" + Constants.RestApiV1.GET_PRODUCTS + "/" + TEST_PRODUCT_ID_1 + "?baseStore=b200").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType("application/json;charset=UTF-8"))
.andExpect(jsonPath("$.productId").value(TEST_PRODUCT_ID_1))
.andExpect(jsonPath("$.name").value("WRX3000"))
.andExpect(jsonPath("$.fullName").value("WRX3000"))
.andExpect(jsonPath("$.regionPickupAvailable").value(false)) // a100 != b200
.andExpect(jsonPath("$.regionDeliveryAvailable").value(true)) // b200 == b200
.andExpect(jsonPath("$.categoryId").value(100500))
.andExpect(jsonPath("$.brandName").value("Samsung"));
}
}
问题是当我从 IDE (Intellij IDEA) 开始这个测试时它工作正常并生成所有片段。但是当我 运行 maven "package" 任务测试失败时
结果:
Tests in error:
testGetProduct(ru.eldorado.searchservice.web.controllers.rest.ProductApiControllerTest): com.fasterxml.jackson.core.JsonParseException: Invalid UTF-8 middle byte 0xe5
我检查过问题出在字段描述中。如果我删除这个部分包目标执行正常。
我的项目和所有输出文件的编码都是 UTF-8。在 Maven 中我明确指定
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
任何帮助和想法将不胜感激。
回答我自己的问题。
问题出在此处的俄语字符中
public static final Product TEST_PRODUCT_1 = Product.builder()
.id(TEST_PRODUCT_ID_1)
.productId(TEST_PRODUCT_ID_1)
.name("WRX3000")
.fullName("WRX3000")
.regionPickupAvailable(Arrays.asList("a100"))
.regionDeliveryAvailable(Arrays.asList("b200"))
.categoryId(100500)
.categoryName("Телевизоры")
.categories(Arrays.asList(10L, 20L, 30L))
.brandId(200300)
.brandName("Samsung")
.description("AMOLED HD Телевизор 4 поколения")
.prices(Arrays.asList(Price.builder().baseStore("b200").priceId(777).priceValue(2990d).oldPriceValue(3490d).build()))
.build();
我添加了方法
private static String getStringInUtf8(String source) {
return new String(source.getBytes(StandardCharsets.UTF_8));
}
并用它在 TEST_PRODUCT_1 声明
中分配包含俄语字符的值
public static final Product TEST_PRODUCT_1 = Product.builder()
.id(TEST_PRODUCT_ID_1)
.productId(TEST_PRODUCT_ID_1)
.name("WRX3000")
.fullName("WRX3000")
.regionPickupAvailable(Arrays.asList("a100"))
.regionDeliveryAvailable(Arrays.asList("b200"))
.categoryId(100500)
.categoryName(getStringInUtf8("Телевизоры"))
.categories(Arrays.asList(10L, 20L, 30L))
.brandId(200300)
.brandName("Samsung")
.description(getStringInUtf8("Super AMOLED HD Телевизор 5 поколения"))
.prices(Arrays.asList(Price.builder().baseStore("b200").priceId(777).priceValue(2990d).oldPriceValue(3490d).build()))
.build();
问题解决了,但还没有找到根源。
我的另一个答案只是一种解决方法。真正的问题在于俄语版本 (Cp-1251) 的标准 Windows 编码。不知何故maven参数没有解决这个问题。但是环境变量
JAVA_TOOL_OPTIONS = -Dfile.encoding=UTF8
修复了一切。
答案已经在这里 How to configure encoding in maven
请帮助我解决我在使用 Spring Rest 文档时遇到的问题。 我已经根据 Spring 手册进行了所有必需的设置。 我写了 Spring MVC 测试。这是代码。奇怪的符号是俄语。
@WebAppConfiguration
@ContextConfiguration(classes = {TestConfiguration.class})
@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles({"test"})
@Slf4j
public class ProductApiControllerTest {
protected static final long TEST_PRODUCT_ID_1 = 11_071_076_993L;
protected static final long TEST_PRODUCT_ID_2 = 21_071_076_994L;
public static final Product TEST_PRODUCT_1 = Product.builder()
.id(TEST_PRODUCT_ID_1)
.productId(TEST_PRODUCT_ID_1)
.name("WRX3000")
.fullName("WRX3000")
.regionPickupAvailable(Arrays.asList("a100"))
.regionDeliveryAvailable(Arrays.asList("b200"))
.categoryId(100500)
.categoryName("Телевизоры")
.categories(Arrays.asList(10L, 20L, 30L))
.brandId(200300)
.brandName("Samsung")
.description("AMOLED HD Телевизор 4 поколения")
.prices(Arrays.asList(Price.builder().baseStore("b200").priceId(777).priceValue(2990d).oldPriceValue(3490d).build()))
.build();
@Mock
private SearchService searchServiceMock;
@InjectMocks
private ProductApiController controller;
private MockMvc mockMvc;
private RestDocumentationResultHandler document;
@Rule
public final RestDocumentation restDocumentation = new RestDocumentation("target/generated-snippets");
@Before
public void init() {
MockitoAnnotations.initMocks(this);
this.document = document("{method-name}", preprocessResponse(prettyPrint()));
mockMvc = MockMvcBuilders.standaloneSetup(controller)
.apply(documentationConfiguration(this.restDocumentation).snippets().withEncoding("UTF-8"))
.alwaysDo(document)
.build();
}
@Test
public void testGetProduct() throws Exception {
log.info("Test getProduct(..) from ProductApiController");
when(searchServiceMock.findByProductId(TEST_PRODUCT_ID_1, "b200")).thenReturn(TEST_PRODUCT_1);
this.document.snippets(responseFields(
fieldWithPath("id").description("Идентификатор для служебных целей поисковой машины."),
fieldWithPath("name").description("Название продукта"),
fieldWithPath("fullName").description("Полное название продукта"),
fieldWithPath("productId").description("Идентификатор (SKU) товара"),
fieldWithPath("regionPickupAvailable").description("Показывает доступен ли продукт для самовывоза в данном регионе"),
fieldWithPath("regionDeliveryAvailable").description("Показывает доступен ли продукт для доставки в данном регионе"),
fieldWithPath("categoryId").description("Идентификатор категории, к которой принадлежит товар"),
fieldWithPath("categoryName").description("Название категории, к которой принадлежит товар"),
fieldWithPath("categories").description("Список идентификаторов категорий к которым принадлежит товар"),
fieldWithPath("brandId").description("Идентификатор бренда товара"),
fieldWithPath("brandName").description("Название бренда продукта"),
fieldWithPath("description").description("Описание товара"),
fieldWithPath("propertyAggregate").description("Какая-то фигня"),
fieldWithPath("propepropertyAggregatertyMap").description("Дополнительные свойства товара"),
fieldWithPath("price").description("Цена товара"),
fieldWithPath("oldPrice").description("Предыдущая цена товара")
));
mockMvc.perform(get(Constants.RestApiV1.ROOT_PATH + "/" + Constants.RestApiV1.GET_PRODUCTS + "/" + TEST_PRODUCT_ID_1 + "?baseStore=b200").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType("application/json;charset=UTF-8"))
.andExpect(jsonPath("$.productId").value(TEST_PRODUCT_ID_1))
.andExpect(jsonPath("$.name").value("WRX3000"))
.andExpect(jsonPath("$.fullName").value("WRX3000"))
.andExpect(jsonPath("$.regionPickupAvailable").value(false)) // a100 != b200
.andExpect(jsonPath("$.regionDeliveryAvailable").value(true)) // b200 == b200
.andExpect(jsonPath("$.categoryId").value(100500))
.andExpect(jsonPath("$.brandName").value("Samsung"));
}
}
问题是当我从 IDE (Intellij IDEA) 开始这个测试时它工作正常并生成所有片段。但是当我 运行 maven "package" 任务测试失败时 结果:
Tests in error:
testGetProduct(ru.eldorado.searchservice.web.controllers.rest.ProductApiControllerTest): com.fasterxml.jackson.core.JsonParseException: Invalid UTF-8 middle byte 0xe5
我检查过问题出在字段描述中。如果我删除这个部分包目标执行正常。
我的项目和所有输出文件的编码都是 UTF-8。在 Maven 中我明确指定
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
任何帮助和想法将不胜感激。
回答我自己的问题。 问题出在此处的俄语字符中
public static final Product TEST_PRODUCT_1 = Product.builder()
.id(TEST_PRODUCT_ID_1)
.productId(TEST_PRODUCT_ID_1)
.name("WRX3000")
.fullName("WRX3000")
.regionPickupAvailable(Arrays.asList("a100"))
.regionDeliveryAvailable(Arrays.asList("b200"))
.categoryId(100500)
.categoryName("Телевизоры")
.categories(Arrays.asList(10L, 20L, 30L))
.brandId(200300)
.brandName("Samsung")
.description("AMOLED HD Телевизор 4 поколения")
.prices(Arrays.asList(Price.builder().baseStore("b200").priceId(777).priceValue(2990d).oldPriceValue(3490d).build()))
.build();
我添加了方法
private static String getStringInUtf8(String source) {
return new String(source.getBytes(StandardCharsets.UTF_8));
}
并用它在 TEST_PRODUCT_1 声明
中分配包含俄语字符的值public static final Product TEST_PRODUCT_1 = Product.builder()
.id(TEST_PRODUCT_ID_1)
.productId(TEST_PRODUCT_ID_1)
.name("WRX3000")
.fullName("WRX3000")
.regionPickupAvailable(Arrays.asList("a100"))
.regionDeliveryAvailable(Arrays.asList("b200"))
.categoryId(100500)
.categoryName(getStringInUtf8("Телевизоры"))
.categories(Arrays.asList(10L, 20L, 30L))
.brandId(200300)
.brandName("Samsung")
.description(getStringInUtf8("Super AMOLED HD Телевизор 5 поколения"))
.prices(Arrays.asList(Price.builder().baseStore("b200").priceId(777).priceValue(2990d).oldPriceValue(3490d).build()))
.build();
问题解决了,但还没有找到根源。
我的另一个答案只是一种解决方法。真正的问题在于俄语版本 (Cp-1251) 的标准 Windows 编码。不知何故maven参数没有解决这个问题。但是环境变量
JAVA_TOOL_OPTIONS = -Dfile.encoding=UTF8
修复了一切。 答案已经在这里 How to configure encoding in maven