0

Dear spring Java professionals

please help me out in this : I have a custom service in spring and I dont have any errors on my wildfly server when i run it . but when I do the below update request i am getting 400 bad request though im sending the format as specified in my controller

inside my controller :

@RequestMapping(value = "/user/updatefilters/{Id}", method = RequestMethod.POST)
    public Response updateFilter(@PathVariable("Id") Long Id, @RequestBody @Valid Filter Filter) {

        FilterService.updateFilter(Id, Filter);

        HashMap<String, Object> response = new HashMap<>();
        response.put("messages", null);
        response.put("success", Boolean.valueOf(true));
        return Response.instance().friendlyName("filter-updated").object(response).statusCode(HttpStatus.OK);
}

inside my service file :

public void updateFilter(Long Id,Filter Filter) {
    List<Filter> currentFilter = FilterRepo.getFilters(Id, Filter.getFilterId().longValue(),null);
    currentFilter.get(0).setLabel(Filter.getLabel());
    FilterRepo.save(currentFilter.get(0));

    for (FilterField FilterField : Filter.getFilterFields()) {
        FilterField currentFilterField = FilterFieldRepo.getFilterField(FilterField.getfieldId());
        if (currentFilterField != null) {
            currentFilterField.setfield(FilterField.getfield());
            currentFilterField.setTypeId(FilterField.getTypeId());
            FilterFieldRepo.save(currentFilterField);
        }           
    }   
}

inside my repository :

public List<Filter> getFilterList(Long Id, String type) {
    List<Filter> FilterField = FilterFieldRepo.getFilterFields(Id,type);
    return FilterField;
}   

public void updateFilter(Long Id,Filter Filter) {
    List<Filter> currentFilter = FilterRepo.getFilters(Id, Filter.getFilterId().longValue(),null);
    currentFilter.get(0).setLabel(Filter.getLabel());
    FilterRepo.save(currentFilter.get(0));

    for (FilterField FilterField : Filter.getFilterFields()) {
        FilterField currentFilterField = FilterFieldRepo.getFilterField(FilterField.getfieldId());
        if (currentFilterField != null) {
            currentFilterField.setfield(FilterField.getfield());
            currentFilterField.setTypeId(FilterField.getTypeId());
            FilterFieldRepo.save(currentFilterField);
        }           
    }   
}

Please note that inside my entity I added a transient list like this :

@Transient
private List<FilterField> filterFields;

updated : this is my Filter class i generated the crud in netbeans but added the transuent list manually:

@Entity
@Table(schema="hitmeister",name = "filters")
@NamedQueries({
    @NamedQuery(name = "Filter.findAll", query = "SELECT s FROM Filter s"),
    @NamedQuery(name = "Filter.findByFilterId", query = "SELECT s FROM Filter s WHERE s.filterId = :filterId"),
    @NamedQuery(name = "Filter.findById", query = "SELECT s FROM Filter s WHERE s.Id = :Id"),
    @NamedQuery(name = "Filter.findByLabel", query = "SELECT s FROM Filter s WHERE s.label = :label"),
    @NamedQuery(name = "Filter.findByInsertionDate", query = "SELECT s FROM Filter s WHERE s.insertionDate = :insertionDate"),
    @NamedQuery(name = "Filter.findByIsActive", query = "SELECT s FROM Filter s WHERE s.isActive = :isActive"),
    @NamedQuery(name = "Filter.findByType", query = "SELECT s FROM Filter s WHERE s.type = :type")})
public class Filter implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "filter_id")
    private Integer filterId;
    @Basic(optional = false)
    @NotNull
    @Column(name = "id")
    private int Id;
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 500)
    @Column(name = "label")
    private String label;
    @Basic(optional = true)
    @Column(name = "insertion_date")
    @Temporal(TemporalType.TIMESTAMP)
    private Date insertionDate;
    @Column(name = "is_active")
    private Boolean isActive;
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 20)
    @Column(name = "type")
    private String type;

    @Transient
    private List<FilterField> filterFields;

    public Filter() {
    }

    public Filter(Integer filterId) {
        this.filterId = filterId;
    }

    public Filter(Integer filterId, int Id, String label, Date insertionDate, String type) {
        this.filterId = filterId;
        this.Id = Id;
        this.label = label;
        this.insertionDate = insertionDate;
        this.type = type;
    }

    public Integer getFilterId() {
        return filterId;
    }

    public void setFilterId(Integer filterId) {
        this.filterId = filterId;
    }

    public int getId() {
        return Id;
    }

    public void setuserId(int Id) {
        this.userId = userId;
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public Date getInsertionDate() {
        return insertionDate;
    }

    public void setInsertionDate(Date insertionDate) {
        this.insertionDate = insertionDate;
    }

    public Boolean getIsActive() {
        return isActive;
    }

    public void setIsActive(Boolean isActive) {
        this.isActive = isActive;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
    @Override
    public int hashCode() {
        int hash = 0;
        hash += (filterId != null ? filterId.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Filter)) {
            return false;
        }
        Filter other = (Filter) object;
        if ((this.filterId == null && other.filterId != null) || (this.filterId != null && !this.filterId.equals(other.filterId))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return " Filter #"+ filterId ;
    }

    public List<FilterField> getFilterFields() {
        return filterFields;
    }

    public void setFilterFields(List<FilterField> filterFields) {
        this.filterFields = filterFields;
    }


}

If you need my entity code i can post it as well Thanks In advance !

sisimh
  • 1,287
  • 3
  • 20
  • 37
  • What `FilterFieldRepo.save(currentFilterField);` doing?? Is this from where you are getting 400 or you mean your browser to server is 400?? Its not clear. – hagrawal7777 Jul 17 '15 at 14:04
  • There should be an error in the logs... Can you post it? – jny Jul 17 '15 at 14:24
  • When I request from my browser it's giving me 400 @hagrawal – sisimh Jul 17 '15 at 14:46
  • @jny no error in jboss console i don't have compilation error , which other log shall I check ? – sisimh Jul 17 '15 at 14:48
  • Do you have an application log? – jny Jul 17 '15 at 14:57
  • Your service and repository code is really not needed to solve your case, so you may or may not have it, but please provide the URL with which you can trying to send the request. – hagrawal7777 Jul 17 '15 at 15:40
  • 400 often occurs when request body cannot be deserialized. can you provide code for your `Filter` class? – Vladimir Jul 17 '15 at 16:30
  • @Vladimir Personally, I think that this could not be because of request serialization issue, because once server was able to understand the request and from that point onwards if there is any server issue then HTTP 5XX error will be thrown. I can tell this as a fact because in my app, JSON string is sent from client and if there is any JSON format issue which results in serialization exception then there is HTTP 500. HTTP 4XX tells that client has sent something unexpected, and that's what I am guessing and telling in my answer below. I think she not handling GET in her server code. – hagrawal7777 Jul 17 '15 at 17:24
  • if Spring-MVC is unable to bind response body to `Filter` object, it won't even get to the code inside the `@Controller` annotated class, and 400 is exactly the status code it will respond with in this case – Vladimir Jul 17 '15 at 17:35
  • @Vladimir i added my Filter entity code please check it – sisimh Jul 17 '15 at 17:42
  • @hagrawal i an using "Services Manager" from localhost to send the request so I can send post but i suspect the data structure i created not the method – sisimh Jul 17 '15 at 17:44
  • I suppose error is caused by `filterFields` property, since Jackson cannot instantiate it, because List is an interface. You can try changing it to concrete class, ArrayList for example – Vladimir Jul 17 '15 at 17:50
  • Ok, if you are sending a POST request then my guess is wrong. @Vladimir to help now. – hagrawal7777 Jul 17 '15 at 17:58
  • @Vladimir i added ArrayList but having same issue with POST , here is the body format : { "filterId": 0, "Id": 0, "label": "", "insertionDate": "", "isActive": false, "type": "", "filterFields": [ { "fieldId": 0, "typeId": { "typeId": 0, "label": "", "type": "", "inputType": "", "options": "" }, "FilterId": "Filter", "field": "" } ] } – sisimh Jul 17 '15 at 18:06
  • @Vladimir can you please check it with me maybe over teamviewer ? – sisimh Jul 17 '15 at 18:07
  • I am not Spring expert but here are my 2 cents you can try based on the JSON object you have provided and your Filter mapping - (1.) Change `userId` to `Id`, (2.) Have `insertionDate` as NULL, instead of an empty string. – hagrawal7777 Jul 17 '15 at 18:18
  • @hagrawal is right - if you wish to avoid using tons of annotations and rely on convention over configuration - you should make your class conform to java bean convention - have setters and getters with according name for each property. also for debugging purposes you might want to start with `Filter` object without filterFields - i.e. mark it with `@JsonIgnore `. when it binds successfully you can proceed to the next object – Vladimir Jul 17 '15 at 18:28

2 Answers2

1

My first recommendation: (OP tried and it didn't work, she was sending POST request)

Change your mapping as below and I think you should be fine. Request from browser address bar is a GET request.

As you can see below, HTTP 400 comes when server is unable to understand the request client is sending, and in your case you are sending GET but server has nothing for GET but for POST, so 400.

W3C HTTP 400

10.4.1 400 Bad Request

The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications.

Code fix:

@RequestMapping(value = "/user/updatefilters/{Id}", method = RequestMethod.GET)


My second recommendation:

I am not Spring expert but here are my 2 cents you can try based on the JSON object you have provided and your Filter mapping - (1.) Change userId to Id, (2.) Have insertionDate as NULL, instead of an empty string.

Make sure your JSON string variables are mapped case-sensitively with your Filter class mapping, and their values are compatible with reference types.

hagrawal7777
  • 14,103
  • 5
  • 40
  • 70
0

Either your request format is not what Spring expects, or one of the Filter validations is failing. Add a org.springframework.validation.Errors argument and dump the values to find out what validations failed.

public Response updateFilter(@PathVariable("Id") Long Id, @RequestBody @Valid Filter Filter, Errors filterErrors) {

You can sniff the actual traffic using curl or a network monitoring tool to make sure the HTTP transaction is really what you think it is.

EDIT: Having looked at the JSON in one of your comments, I think this is going to turn out to be upper/lower case in your JSON field names. Either change "Id" to "id" and "FilterId" to "filterId", or annotate the Filter fields with @XmlElement(name = "Id") and @XmlElement(name = "FilterId"). Java Bean property names are case sensitive.

EDIT 2: Filter.setuserId(int Id) is broken as well. You need a setId() method for deserializing the bean, and you need to change the method so it stores the passed argument instead of just setting userId to itself.

Kevin Condon
  • 1,618
  • 10
  • 16
  • thanks @Kevin Condon , so adding org.springframework.validation.Errors wont enable me to see errors unless I have a monitoring tool ? – sisimh Jul 17 '15 at 21:37
  • You won't need network monitoring, just some added code to print out the data from the injected `Errors` argument. Something like `if (filterErrors.hasErrors()) { // iterate over filterErrors.getAllErrors() }`. See http://stackoverflow.com/a/7384449/125344. – Kevin Condon Jul 17 '15 at 21:56