wkennedy / swagger4spring-web

Swagger support for Spring MVC
89 stars 46 forks source link

Any idea about processing java.lang.Object failed? #46

Open hunts opened 10 years ago

hunts commented 10 years ago

By my RESTful service, i met following issue which casue the model-schema result in missing many models.

converter.ModelPropertyParser - processing class class java.lang.Object 17:46:50.575 [http-8080-6] DEBUG c.w.s.converter.ModelPropertyParser - processing method public final void java.lang.Object.wait() throws java.lang.InterruptedException 17:46:50.575 [http-8080-6] DEBUG c.w.s.converter.ModelPropertyParser - processing method public java.lang.String java.lang.Object.toString() 17:46:50.575 [http-8080-6] DEBUG c.w.s.converter.ModelPropertyParser - processing method public native int java.lang.Object.hashCode() 17:46:50.575 [http-8080-6] DEBUG c.w.s.converter.ModelPropertyParser - processing method public final native java.lang.Class java.lang.Object.getClass() 17:46:50.575 [http-8080-6] DEBUG c.w.s.converter.ModelPropertyParser - inspecting null 17:46:50.575 [http-8080-6] DEBUG c.w.s.converter.ModelPropertyParser - skipping class

wkennedy commented 10 years ago

Hello, is there anyway you can provide me with any more information? Possibly the class that is missing?

hunts commented 10 years ago

HI Wkennedy, My classes are like this:

package com.example.nfss.model.response;

/**
 * @author Hunts
 * @date Dec 14, 2013 2:35:41 PM
 */
public interface BizResponse {

    /**
     * Returns JSON string.
     * 
     * @return
     */
    String toJson();
}
package com.example.nfss.model.response;

import org.apache.log4j.Logger;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.knappsack.swagger4springweb.annotation.ApiExclude;
import com.example.nfss.model.request.QueryOptions;
import com.example.nfss.utils.R;
import com.example.nfss.utils.json.ResponseObjectMapper;
import com.wordnik.swagger.annotations.ApiModelProperty;

/**
 * 
 * 
 * @author Hunts
 * @date Jan 3, 2014 1:36:30 PM
 */
@JsonInclude(Include.NON_NULL)
public abstract class AbstractResponse implements BizResponse {

    private static final Logger LOG = Logger.getLogger(AbstractResponse.class);

    protected final QueryOptions options;

    /**
     * 
     * @param options
     */
    public AbstractResponse(final QueryOptions options) {
        this.options = options;
    }

    @ApiExclude
    @Override
    public String toJson() {

        if(options == null)
            return R.STR_JSON_EMPTY;

        ObjectMapper mapper = new ResponseObjectMapper();
        ObjectWriter ow = mapper.writer();

        ow = ow.withDefaultPrettyPrinter();

        try {
            return ow.writeValueAsString(this);
        } catch (JsonProcessingException e) {
            LOG.error(e.toString());
        }

        return R.STR_JSON_EMPTY;
    }
}
package com.example.nfss.model.response;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.example.nfss.model.product.ProductCollection;
import com.example.nfss.model.request.QueryOptions;
import com.wordnik.swagger.annotations.ApiModel;
import com.wordnik.swagger.annotations.ApiModelProperty;

/**
 * Represents search response.
 * 
 * @author Hunts
 * @date Dec 18, 2013 1:37:58 PM
 */
@ApiModel(value="search result", parent=AbstractResponse.class)
@JsonInclude(Include.NON_NULL)
public class SearchResponse extends AbstractResponse {

    private ProductCollection products;

    /**
     * @param options
     */
    public SearchResponse(final QueryOptions options) {
        super(options);
    }

    /**
     * Returns products.
     * 
     * @return
     */
    @ApiModelProperty(value="collection of products", position=1)
    public ProductCollection getProducts() {
        return products;
    }

    public void setProducts(ProductCollection products) {
        this.products = products;
    }
}
package com.example.nfss.model.product;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.knappsack.swagger4springweb.annotation.ApiExclude;
import com.wordnik.swagger.annotations.ApiModel;
import com.wordnik.swagger.annotations.ApiModelProperty;

/**
 * Represents collection of products.
 * 
 * @author Hunts
 * @date Dec 14, 2013 3:45:18 PM
 */
@ApiModel(value="collection of products")
@JsonInclude(Include.NON_EMPTY)
public class ProductCollection implements Iterable<ProductInfo>, Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * Gets or sets total matched records.
     */
    @ApiModelProperty(value="total matched items", required=true)
    @JsonProperty(value="totalHits", required=true)
    public long totalHits;

    /**
     * Gets or sets record list.
     */
    @ApiModelProperty(value="item list", required=true)
    @JsonProperty(value="items", required=true)
    public final List<ProductInfo> items;

    public ProductCollection() {
        items = new ArrayList<ProductInfo>();
    }

    @ApiExclude
    @JsonIgnore
    @Override
    public Iterator<ProductInfo> iterator() {
        return items.iterator();
    }

    public void add(final ProductInfo product){
        items.add(product);
    }

    public void addAll(final List<ProductInfo> products){
        items.addAll(products);
    }
}
package com.example.nfss.model.product;

import java.util.Date;

import org.apache.solr.client.solrj.beans.Field;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.example.nfss.model.product.mapping.SolrFieldMeta;
import com.wordnik.swagger.annotations.ApiModel;

/**
 * Represents product detail info.
 * 
 * @author Hunts Chen
 * @date Dec 18, 2013 1:29:34 PM
 */
@ApiModel(value="product info")
@JsonInclude(Include.NON_EMPTY)
public class ProductInfo {

    public static final String FIELD_ITEM_NUMBER = "item_number";
    public static final String FIELD_DISCOUNT_MARK = "discount_mark";
    public static final String FIELD_UNIT_PRICE = "unit_price";
    public static final String FIELD_DISCOUNT_INSTANT = "discount_instant";
    public static final String FIELD_AVAIL_QTY = "avail_qty";
    public static final String FIELD_DESCRIPTION = "description";
    public static final String FIELD_START_TIME = "start_time";
    public static final String FIELD_EXPIRE_TIME = "expire_time";
    public static final String FIELD_ACTIVE = "active";
    public static final String FIELD_ITEM_CATALOG = "item_catalog";
    public static final String FIELD_SUBCATEGORY_NAME = "subcategory_name";

    @Field(FIELD_ITEM_NUMBER)
    @SolrFieldMeta(field = FIELD_ITEM_NUMBER, searchable=true, indexed=true)
    private String itemNumber;

    @Field(FIELD_UNIT_PRICE)
    @SolrFieldMeta(field = FIELD_UNIT_PRICE)
    private double unitPrice;

    @Field(FIELD_DISCOUNT_INSTANT)
    @SolrFieldMeta(field = FIELD_DISCOUNT_INSTANT)
    private double discountInstant;

    @Field(FIELD_AVAIL_QTY)
    @SolrFieldMeta(field = FIELD_AVAIL_QTY, indexed=true)
    private int availQty;

    @Field(FIELD_DESCRIPTION)
    @SolrFieldMeta(field = FIELD_DESCRIPTION, searchable=true)
    private String description;

    @Field(FIELD_START_TIME)
    @SolrFieldMeta(field = FIELD_START_TIME, indexed=true)
    private Date startTime;

    @Field(FIELD_EXPIRE_TIME)
    @SolrFieldMeta(field = FIELD_EXPIRE_TIME, indexed=true)
    private Date expireTime;

    @Field(FIELD_ACTIVE)
    @SolrFieldMeta(field = FIELD_ACTIVE, indexed=true)
    private int active;

    @Field(FIELD_ITEM_CATALOG)
    @SolrFieldMeta(field = FIELD_ITEM_CATALOG, indexed=true)
    private int itemCatalog;

    @Field(FIELD_SUBCATEGORY_NAME)
    @SolrFieldMeta(field = FIELD_SUBCATEGORY_NAME, searchable=true, indexed=true)
    private String subcategoryName;

    /**
     * 
     */
    public ProductInfo() {
    }

    /**
     * @return the itemNumber
     */
    public String getItemNumber() {
        return itemNumber;
    }
    /**
     * @param itemNumber the itemNumber to set
     */
    public void setItemNumber(String itemNumber) {
        this.itemNumber = itemNumber;
    }
    /**
     * @return the unitPrice
     */
    public double getUnitPrice() {
        return unitPrice;
    }
    /**
     * @param unitPrice the unitPrice to set
     */
    public void setUnitPrice(double unitPrice) {
        this.unitPrice = unitPrice;
    }
    /**
     * @return the discountInstant
     */
    public double getDiscountInstant() {
        return discountInstant;
    }
    /**
     * @param discountInstant the discountInstant to set
     */
    public void setDiscountInstant(double discountInstant) {
        this.discountInstant = discountInstant;
    }

    /**
     * @return the availQty
     */
    public int getAvailQty() {
        return availQty;
    }
    /**
     * @param availQty the availQty to set
     */
    public void setAvailQty(int availQty) {
        this.availQty = availQty;
    }
    /**
     * @return the description
     */
    public String getDescription() {
        return description;
    }
    /**
     * @param description the description to set
     */
    public void setDescription(String description) {
        this.description = description;
    }
    /**
     * @return the startTime
     */
    public Date getStartTime() {
        return startTime;
    }
    /**
     * @param startTime the startTime to set
     */
    public void setStartTime(Date startTime) {
        this.startTime = startTime;
    }
    /**
     * @return the expireTime
     */
    public Date getExpireTime() {
        return expireTime;
    }
    /**
     * @param expireTime the expireTime to set
     */
    public void setExpireTime(Date expireTime) {
        this.expireTime = expireTime;
    }
    /**
     * @return the active
     */
    public boolean isActive() {
        return active == 1;
    }
    /**
     * @param active the active to set
     */
    public void setActive(int active) {
        this.active = active;
    }
    /**
     * @return the itemCatalog
     */
    public int getItemCatalog() {
        return itemCatalog;
    }
    /**
     * @param itemCatalog the itemCatalog to set
     */
    public void setItemCatalog(int itemCatalog) {
        this.itemCatalog = itemCatalog;
    }
    /**
     * @return the subcategoryName
     */
    public String getSubcategoryName() {
        return subcategoryName;
    }
    /**
     * @param subcategoryName the subcategoryName to set
     */
    public void setSubcategoryName(String subcategoryName) {
        this.subcategoryName = subcategoryName;
    }
}

Thanks

hunts commented 10 years ago

And the controller is:

package com.example.nfss.api.controllers;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.example.nfss.api.AbstractRequest;
import com.example.nfss.api.SearchRequest;
import com.example.nfss.model.response.BizResponse;
import com.example.nfss.model.response.ErrorResponse;
import com.example.nfss.model.response.SearchResponse;

import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiImplicitParam;
import com.wordnik.swagger.annotations.ApiImplicitParams;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
import com.wordnik.swagger.annotations.ApiResponse;
import com.wordnik.swagger.annotations.ApiResponses;

/**
 * Search REST Controller.
 * 
 * @author Hunts
 * @date Dec 17, 2013 11:46:29 AM
 */
@Controller
@RequestMapping("/v1")
@Api(value = "/v1", description = "APIs about search and search suggestion")
public class RestController {

    /**
     * 
     * @param parameters
     * @return
     */
    @ApiOperation(
            value = "Common search"
            , notes = "Returns a collection of relevant products"
            , response = SearchResponse.class
            , httpMethod = "GET"
            )
    @ApiResponses({
        @ApiResponse(code = 200, message = "OK")
        , @ApiResponse(code = 500, message = "Process error")
        })
    @RequestMapping(value = "/search", method = RequestMethod.GET, produces="application/json")
    public ResponseEntity<BizResponse> search(
            @ApiParam(name=QueryOptions.PARAM_APP, value = "client name", allowableValues="Web", defaultValue="Web", required=true)
            final @RequestParam MultiValueMap<String, String> parameters
            ) {

        AbstractRequest req = new SearchRequest(parameters);
        BizResponse resp = req.getResponse();

        return createResponseEntity(resp);
    }

    /**
     * Construct a HTTP response entity.
     * 
     * @param resp The business response object.
     * @return A response entity.
     */
    private ResponseEntity<BizResponse> createResponseEntity(BizResponse resp) {
        if(resp instanceof ErrorResponse) {
            return new ResponseEntity<BizResponse>(resp, HttpStatus.INTERNAL_SERVER_ERROR);
        }

        return new ResponseEntity<BizResponse>(resp, HttpStatus.OK);
    }
}
bpbhat77 commented 9 years ago

:+1: same issue here :( but without spring