Spring MVC генерирует исключение с помощью Google Protobuf 3 - PullRequest
0 голосов
/ 10 апреля 2019

Ребята, вы должны мне помочь, пожалуйста!

Мое приложение генерирует следующую ошибку при использовании repeat, fixed64 или int64.

com.google.protobuf.InvalidProtocolBufferException: While parsing a protocol message, the input ended unexpectedly in the middle of a field.  This could mean either that the input has been truncated or that an embedded message misreported its own length.
at com.google.protobuf.InvalidProtocolBufferException.truncatedMessage(InvalidProtocolBufferException.java:86)
at com.google.protobuf.CodedInputStream$ArrayDecoder.pushLimit(CodedInputStream.java:1224)
at com.google.protobuf.CodedInputStream$ArrayDecoder.readMessage(CodedInputStream.java:921)
at com.google.protobuf.AbstractParser.parsePartialFrom(AbstractParser.java:163)
at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:197)
at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:209)
at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:214)
at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:49)
at ...

** Проект 1 **

Мой файл Protobuf

syntax = "proto3";

option java_package = "br.com.my.project.view";
option java_outer_classname = "CompanyProtos";

message CompanyResponse {
  repeated Company companies = 1;
}
message Company {
  string name = 1;
  fixed32 id = 2;
  fixed64 systemId = 3;
  string aliasName = 4;
  message Address {
    fixed32 addressTypeId = 1;
    string streetType = 2;
    string streetName = 3;
    string streetNumber = 4;
    string streetComplement = 5;
    string neighborhood = 6;
    string city = 7;
    string state = 8;
    string country = 9;
    string zipcode = 10;
  }
  Address address = 5;
  message Phone {
    string name = 1;
    fixed64 number = 2;
  }
  repeated Phone phones = 6;
}

Spring Config class

@Configuration
public class SpringConfig extends WebMvcConfigurationSupport {

@Bean
public ViewResolver internalResourceViewResolver() {
    InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
    viewResolver.setViewClass(JstlView.class);
    viewResolver.setPrefix("/WEB-INF/views/");
    viewResolver.setSuffix(".jsp");
    return viewResolver;
}

@Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.add(protobufJsonFormatHttpMessageConverter());
    super.configureMessageConverters(converters);
}

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/index.jsp");
}

@Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
    return new PropertySourcesPlaceholderConfigurer();
}

@Bean
public ProtobufJsonFormatHttpMessageConverter protobufJsonFormatHttpMessageConverter() {
    return new ProtobufJsonFormatHttpMessageConverter();
}
}

Класс контроллера

@RestController
@RequestMapping("company")
public class CompanyController {

   @Autowired
   private ICompanyBusinessService companyBusinessService;

   @GetMapping(value = {"/name/{name}"},produces = {MediaType.APPLICATION_JSON_UTF8_VALUE,"application/x-protobuf;charset=UTF-8" })
   public CompanyProtos.CompanyResponse getProtobufCompany(
        @RequestHeader(value = "messageId", required = false) String tid,
        @PathVariable(value = "name", required = false) String name) {

    List<Company> companies = companyBusinessService.getCompanies(name);
    CompanyProtos.CompanyResponse.Builder builder = CompanyProtos.CompanyResponse.newBuilder();
    for(Company c : companies) {
        CompanyProtos.Company.Builder companyBuilder = CompanyProtos.Company.newBuilder();
        companyBuilder.setName(c.getName());
        companyBuilder.setId(c.getId());
        companyBuilder.setSystemId(c.getSystemId());
        companyBuilder.setAliasName(c.getAliasName());

        CompanyProtos.Company.Address.Builder addressBuilder = CompanyProtos.Company.Address.newBuilder();
        addressBuilder.setAddressTypeId(c.getAddress().getAddressTypeId());
        addressBuilder.setStreetType(c.getAddress().getStreetType());
        addressBuilder.setStreetName(c.getAddress().getStreetName());
        addressBuilder.setStreetNumber(c.getAddress().getStreetNumber());
        addressBuilder.setStreetComplement(c.getAddress().getStreetComplement());
        addressBuilder.setNeighborhood(c.getAddress().getNeighborhood());
        addressBuilder.setCity(c.getAddress().getCity());
        addressBuilder.setState(c.getAddress().getState());
        addressBuilder.setCountry(c.getAddress().getCountry());
        addressBuilder.setZipcode(c.getAddress().getZipcode());
        addressBuilder.setMailbox(c.getAddress().getMailbox());
        companyBuilder.setAddress(addressBuilder.build()); 

        for(Phone p : c.getPhones()) {
            CompanyProtos.Company.Phone.Builder phoneBuilder = CompanyProtos.Company.Phone.newBuilder();
            phoneBuilder.setName(p.getName());
            phoneBuilder.setNumber(p.getNumber());
            companyBuilder.addPhones(phoneBuilder.build());
        }

        builder.addCompanies(companyBuilder.build());
    }
    return builder.build();
 }
}

** Проект 2 **

Мой еще один проект. получатель.

....

private ResponseEntity<byte[]> performCall(URI uri, HttpHeaders headers, HttpMethod method) throws Exception {
    RestTemplate rest = new RestTemplate();
    rest.getMessageConverters().add(new ProtobufHttpMessageConverter());
    rest.getMessageConverters().add(new StringHttpMessageConverter());
    rest.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
    rest.getMessageConverters().add(new ByteArrayHttpMessageConverter());
    HttpEntity<String> request = new HttpEntity<>(headers);
    ResponseEntity<byte[]> response = rest.exchange(uri, method, request, byte[].class);
    return response;
}

public byte[] perform() throws Exception {
    UriComponentsBuilder builder = UriComponentsBuilder.fromUriString("http://localhost:8080/company/name/MyCompany")
    HttpHeaders headers = new HttpHeaders();
    headers.set("Accept","application/x-protobuf;charset=UTF-8");
    ResponseEntity<byte[]> response = this.performCall(uri, headers, HttpMethod.GET);
    return response.getBody();
}

private convertProtobufToObject(){
try {
        byte[] result = perform();
        CompanyProtos.CompanyResponse companies = CompanyProtos.CompanyResponse.parseFrom(result);
        System.out.println();
    } catch (Exception e) {
        e.printStrackTrace();
    }
}

....

Я использую Spring 5.1.4, protobuf-java 3.6.1, protobuf-java-util 3.6.1, protobuf-java-format 1.4, Tomcat 9 и spring-boot-зависимости 2.1.2.RELEASE и .proto файл одинаков для двух проектов.

Когда я использую parseFrom в проекте 1, он работает, но когда я использую в проекте 2, не работает!

** ОБНОВЛЕНИЕ **

Ну, после нескольких тестов я нашел ответ. Проблема была в кодировке Windows (CP1252). Мне нужно было добавить эту конфигурацию при запуске tomcat9:

-Dfile.encoding = CP1252

это работает, но не работает с UTF-8

Вы можете мне помочь?

Спасибо

1 Ответ

0 голосов
/ 23 апреля 2019

Решено

Мне нужно было создать класс AbstractHttpMessageConverter и реализовать writeInternal, где я преобразовал байтовый массив в Base64.Тогда я просто изменил процесс в readInternal

...