PUT request from Android using spring RestTemplate

2020-04-30 16:41发布

问题:

I have to PUT a customer object from android client to the database through Restful service (.Net)

Service Contract

[WebInvoke(Method = "PUT", UriTemplate = "customers/{customerId}", RequestFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare)]
    [OperationContract]
    ReturnValueLong PutCustomer(string customerId, Customer entity);

Customer.cs

public class Customer
{

    [DataMember]
    public long SystemId{ get; set; } 

    [DataMember]
    public long CustomerId { get; set; }

    [DataMember]
    public string Name { get; set; }

    [DataMember]
    public string Description { get; set; }
}

On the client side I'm using Spring for Android to communicate.

Client Code:

                    Customer customer = new Customer();
                    customer.setCustomerId(12);
                    customer.setName("sample name");
                    customer.setDescription("sample description");
                    customer.setSystemId(123);

                    List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>();
                    acceptableMediaTypes.add(MediaType.APPLICATION_XML);

                    // Prepare header
                    HttpHeaders headers = new HttpHeaders();
                    headers.setAccept(acceptableMediaTypes);

                    // Pass the new person and header
                    HttpEntity<Customer> entity = new HttpEntity<Customer>(
                            customer, headers);

                    final String url = "https://192.168.2.119:8009/IAdministratorService/customers/{customerId}";

                    RestTemplate restTemplate = new RestTemplate();
                    restTemplate.getMessageConverters().add(
                            new SimpleXmlHttpConverter());

                    ResponseEntity<NCheckReturnValue> result = restTemplate
                            .exchange(url, HttpMethod.PUT, entity,
                                    NCheckReturnValue.class, 12);

                    return "Return Code:" + result.getBody().getCode()
                            + " Return Value: "
                            + result.getBody().getReturnValue();

Customer.java

@Root(name = "Customer")
 @Namespace(reference = "NCheck.Core.Model")
 public class Customer {

@Element
private long SystemId;

@Element
private long CustomerId;

@Element
private String Name;

@Element
private String Description;

// Getters and Setters


}

When I execute the code the Customer object not received properly on the Server side. (Name is correct but the Description is null)

What is the wrong with this implementation?

回答1:

If you are able to put 'name', there there is no reason why not 'description'. Generally if an attribute is sent as null, it will be because the annotation is not properly defined. Possible solutions,

  1. You may not need annotation at all for the model class (Customer.java), as the class name, attributes names exactly match at client end and server end.
  2. Double check the name of attributes at the two ends.
  3. Use a proxy tool, like charles or Burpsuite to sniff the structure of request body to ensure that the request is of expected format.
  4. You may try writing something similar suitable to your purpose.

        /**
             * Put operation where where request and response are both JSON objects.
             * 
             * @param request
             *            the Object to be sent as part of request body
             * @param url
             *            the server url for request
             * @param restTemplate
             *            the rest template
             * @param response
             *            the response type that will be returned by server
             * @return the response object
             * @throws Exception
             */
            public T2 put(T1 request, String url, RestTemplate restTemplate,
                    Class<T2> response) throws Exception {
    
                HttpHeaders headers = new HttpHeaders();
                headers.setAcceptEncoding(ContentCodingType.GZIP);
                // use MediaType relevant to your need
                headers.setContentType(new MediaType(APPLICATION, TYPE_JSON));
    
                HttpEntity<T1> requestEntity = new HttpEntity<T1>(request, headers);
                ResponseEntity<T2> responseEntity;
                try {
                    responseEntity = restTemplate.exchange(url, HttpMethod.PUT,
                            requestEntity, response);
    
                } catch (HttpClientErrorException ex) {
                    throw ex;
                }
    
                catch (HttpServerErrorException e) {
                    throw e;
                }
                return responseEntity.getBody();
            }
    

    good luck!



回答2:

Finally I found the solution.

Here the problem is order of elements in XML after serialization. WCF service contract expects the elements in a particular order (Even though it breaks the XML specification). But when serializing using SimpleXmlHttpConverter (I believe it use the Persistor inside) to serialize we can't guarantee the order of elements appear in the XML output.

Solution:

There is a tag available called @Order (org.simpleframework.xml.Order)

@Root(name = "Customer")
@Namespace(reference = "NCheck.Core.Model")
@Order(elements = {"CustomerId", "Description", "Name" })
public class Customer {

@Element
private long CustomerId;

@Element
private String Name;

@Element
private String Description;

public long getCustomerId() {
    return CustomerId;
}
public void setCustomerId(long customerId) {
    CustomerId = customerId;
}
public String getName() {
    return Name;
}
public void setName(String name) {
    Name = name;
}
public String getDescription() {
    return Description;
}
public void setDescription(String description) {
    Description = description;
}
}

Another Solution could be do some changes in the Server Side by using [XmlSerializerFormat] tag on ServiceContracts which doesn't require any order of elements.