0

这是我的资源类:

@Component
@Path("forum/categories")
@Produces(MediaType.APPLICATION_JSON)
public class ForumCategoryResource {

@Context
UriInfo uriInfo;

@Resource(name="forumService")
private ForumService forumService;

@GET
@Path("tree/{rootId}")
@Produces(MediaType.APPLICATION_JSON)
public Response getCategoryTreeById(@PathParam("rootId") Integer rootId) {
    
    System.out.println("Got request for tree by id: " + rootId);
    
    Tree<ForumCategory> tree = forumService.getCategoryTreeById(rootId);
    
    return Response.ok(new GenericEntity<Tree<ForumCategory>>(
            tree, tree.getClass()
    )).build(); 
}

这是我的数据类型泛型类:

public class Tree<T> {
    
    public interface Converter<T, S> {
        S convert (T t);
    }
    
    public enum IterationStrategy {
        PREORDER,
        LEVELORDER,
        POSTORDER
    }
        
    private T value;
    private Tree<T> parent;
    private List<Tree<T>> children;
    private int height;
    
    public Tree(Tree<T> tree) {
        
        this.value = tree.value;
        this.children = createListAdapterForHeightCalculation(tree.children);
        this.parent = tree.parent;
        this.height = tree.height;
    }
    
    public Tree(T value) {
        this.value = value;
        this.children = createListAdapterForHeightCalculation(Lists.<Tree<T>>newArrayList());
        this.height = 1;
    }
    
    public Tree<T> add(Tree<T> tree) {
        children.add(tree);
        tree.parent = this;
        calculateHeightToRoot(tree);
        return tree;
    }
    
    private ListAdapter<Tree<T>> createListAdapterForHeightCalculation(final List<Tree<T>> list) {
        return new ListAdapter<Tree<T>>(list) {
            
            @Override
            public Tree<T> remove(int index) {
                Tree<T> removedElement = super.remove(index);               
                int newMaxHeightAtThisLevel = getMaxHeight(list);
                removedElement.parent.height = newMaxHeightAtThisLevel + 1;
                calculateHeightToRoot(removedElement.parent);
                return removedElement;
            }
    
            private int getMaxHeight(List<Tree<T>> children) {
                
                int result = 0;
                
                for (Tree<T> tree : children) {
                    result = Math.max(tree.height, result);
                }
                
                return result;
            }
        };      
    }

    private void calculateHeight(Tree<T> parent, Tree<T> child) {
        int height = Math.max(parent.height, child.height + 1);
        parent.height = height;
    }
    
    private void calculateHeightToRoot(Tree<T> tree) {

        Tree<T> parent = tree.parent;
        Tree<T> child = tree;
        

        while ( ! child.isRoot() ) {
            calculateHeight(parent, child);
            parent = parent.parent;
            child = child.parent;
        }
    }
    
    public <S> Tree<S> convert(Converter<T, S> converter) {
        
        Tree<S> result = new Tree<S>(converter.convert(this.value));
        
        for (Tree<T> child : this.children) {
            result.add(child.convert(converter));
        }
        
        return result;
    }

    public Tree<T> add(T value) {
        return add(new Tree<T>(value));
    }
    
    public int getHeight() {
        return height;
    }
    
    public Tree<T> getParent() {
        return parent;
    }

    public T getValue() {
        return value;
    }
    
    public List<Tree<T>> getChildren() {
        return children;        
    }
    
    public boolean isRoot() {
        return parent == null;
    }
    
    public boolean isLeaf() {
        return children.isEmpty();
    }
    
    public boolean hasParent() {
        return ! isRoot();
    }
    
    public boolean hasChildren() {
        return ! isLeaf();
    }
        
    @Override
    public String toString() {
        return toString(this, null);
    }

    private String toString(Tree<T> tree, String prefix) {
        
        prefix = (prefix == null) ? "" : prefix;
        
        StringBuilder result = new StringBuilder(prefix + ObjectUtils.toString(tree.value) + ":" + tree.height);
        result.append("\n");
        
        for (Tree<T> child : tree.children) {
            String newPrefix;
            if (StringUtils.isEmpty(prefix)) {
                newPrefix = "|- ";
            }
            else {
                newPrefix = "| " + prefix;
            }
            result.append(toString(child, newPrefix));
        }

        return result.toString();
    }
    
    public List<T> getPathFromRoot() {
        List<T> result = getPathToRoot();
        Collections.reverse(result);
        return result;
    }

    public List<T> getPathToRoot() {
        List<T> result = new ArrayList<T>();
        
        Tree<T> pathElement = this;
        
        while ( ! pathElement.isRoot() ) {
            result.add(pathElement.value);
            pathElement = pathElement.parent;
        }
        
        result.add(pathElement.value);
        return result;
    }
    
    public boolean containsChildWithValue(T value) {
        for (Tree<T> child : children) {
            if (ObjectUtils.equals(value,child.getValue())) return true;
        }
        return false;
    }

    public Tree<T> findFirst(T value) {
        return findFirst(value, IterationStrategy.PREORDER);
    }
    
    public Tree<T> findFirst(T value, IterationStrategy strategy) {
        
        switch (strategy) {
            
            case PREORDER: return findFirstPreOrder(this, value);
            case LEVELORDER: return findFirstLevelOrder(Arrays.asList(this), value);
            case POSTORDER: return findFirstPostOrder(this, value);
        }
        
        return null;
    }

    private Tree<T> findFirstLevelOrder(List<Tree<T>> treeList, T value) {
        
        List<Tree<T>> treeListChildren = new ArrayList<Tree<T>>();

        for (Tree<T> tree : treeList) {
            if (tree.value.equals(value)) {
                return tree;
            }
            
            treeListChildren.addAll(tree.children);
        }
        
        if (treeListChildren.size() > 0) {
            return findFirstLevelOrder(treeListChildren, value);
        }

        return null;
    }

    private Tree<T> findFirstPostOrder(Tree<T> tree, T value) {
        
        for (Tree<T> child : tree.children) {
            Tree<T> result = findFirstPostOrder(child, value);
            if (result != null) {
                return result;
            }
        }
        
        if (tree.value.equals(value)) {
            return tree;
        }
        
        return null;
    }

    private Tree<T> findFirstPreOrder(Tree<T> tree, T value) {
        
        if (tree.value.equals(value)) {
            return tree;
        }
        
        for (Tree<T> child : tree.children) {
            Tree<T> result = findFirstPreOrder(child, value);
            if (result != null) return result;
        }
        
        return null;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((children == null) ? 0 : children.hashCode());
        result = prime * result + height;
        result = prime * result + ((value == null) ? 0 : value.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        @SuppressWarnings("unchecked")
        Tree<T> other = (Tree<T>) obj;
        if (children == null) {
            if (other.children != null)
                return false;
        } else if (!children.equals(other.children))
            return false;
        if (height != other.height)
            return false;
        if (value == null) {
            if (other.value != null)
                return false;
        } else if (!value.equals(other.value))
            return false;
        return true;
    }

}

这是我的域类:

public class ForumCategory {

    private Integer forumCategoryId;
    private String nameKey;
    private String descriptionKey;
    
    public ForumCategory() {
    }
    
    public ForumCategory(String nameKey, String descriptionKey) {
        this.nameKey = nameKey;
        this.descriptionKey = descriptionKey;
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(forumCategoryId).toHashCode();
    }

    @Override
    public boolean equals(Object obj) {

        if (this == obj) {
            return true;
        }

        if (obj == null) {
            return false;
        }
        
        if (getClass() != obj.getClass()) {
            return false;
        }

        ForumCategory other = (ForumCategory) obj;
        return new EqualsBuilder().append(this.forumCategoryId, other.forumCategoryId).isEquals();
    }

    public String getNameKey() {
        return nameKey;
    }

    public void setNameKey(String nameKey) {
        this.nameKey = nameKey;
    }

    public String getDescriptionKey() {
        return descriptionKey;
    }

    public void setDescriptionKey(String descriptionKey) {
        this.descriptionKey = descriptionKey;
    }

    public Integer getForumCategoryId() {
        return forumCategoryId;
    }

    public void setForumCategoryId(Integer forumCategoryId) {
        this.forumCategoryId = forumCategoryId;
    }

    @Override
    public String toString() {
        return "ForumCategory [forumCategoryId=" + forumCategoryId
                + ", nameKey=" + nameKey + ", descriptionKey=" + descriptionKey
                + "]";
    }
    
    
}

这是我的 Tree 类的 MessageBodyWriter:

@Provider
@Produces(MediaType.APPLICATION_JSON)
public class TreeWriter implements MessageBodyWriter<Tree<?>> {
    
    private static final Tree<?> NULL_TREE = new Tree<Object>((Object)null);
    private static final Charset CHARSET = Charset.forName("UTF-8");
    
    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public boolean isWriteable(Class<?> type, Type genericType,
            Annotation[] annotations, MediaType mediaType) {

        System.out.println("isWritable");
        return type == NULL_TREE.getClass();
    }

    @Override
    public long getSize(Tree<?> tree, Class<?> type, Type genericType,
        Annotation[] annotations, MediaType mediaType) {
        System.out.println("getSize");
    
        try {
            return getTreeAsJsonString(tree).length() * Character.SIZE / Byte.SIZE;
        } 
        catch (IOException e) {
            throw new WebApplicationException(e);
        }
    }

    @Override
    public void writeTo(Tree<?> tree, Class<?> type, Type genericType,
            Annotation[] annotations, MediaType mediaType,
            MultivaluedMap<String, Object> httpHeaders,
            OutputStream entityStream) throws IOException,
            WebApplicationException {

        System.out.println("writeTo");
        System.out.println(tree);
        String jsonString = getTreeAsJsonString(tree);
        System.out.println(jsonString);
        entityStream.write(jsonString.getBytes(CHARSET));
        entityStream.flush();
    }
    
    private String getTreeAsJsonString(Tree<?> tree) throws IOException {
        
        if (tree != null) {
            
            StringBuilder result = new StringBuilder();
            appendTree(result, tree);
            return result.toString();
        }
        
        return "null";
    }

    private void appendTree(StringBuilder result, Tree<?> tree) throws IOException {
        
        result.append("{");     
        appendTreeValue(result, tree);
        result.append(",");
        appendTreeChildren(result, tree);
        result.append(",");
        appendTreeHeight(result, tree);
        result.append("}");
        
    }

    private void appendTreeHeight(StringBuilder result, Tree<?> tree) {
        result.append("\"height\":");
        result.append(tree.getHeight());
    }

    private void appendTreeChildren(StringBuilder result, Tree<?> tree) throws IOException {
        
        result.append("\"children\":[");
        
        boolean hasChildren = false;
        
        for (Tree<?> child : tree.getChildren()) {
            appendTree(result, child);
            result.append(",");
            hasChildren = true;
        }
        
        if (hasChildren) {
            result.deleteCharAt(result.length() - 1);
        }

        result.append("]");
    }

    private void appendTreeValue(StringBuilder result, Tree<?> tree) throws IOException {
        result.append("\"value\":");
        result.append(objectMapper.writeValueAsString(tree.getValue()));        
    }
}

我从 System.out.println 代码中得到以下输出:

Got request for tree by id: 1
isWritable
getSize
writeTo
ForumCategory [forumCategoryId=1, nameKey=cat.name.a, descriptionKey=cat.desc.a]:2
|- ForumCategory [forumCategoryId=2, nameKey=a, descriptionKey=b]:1

{"value":{"forumCategoryId":1,"nameKey":"cat.name.a","descriptionKey":"cat.desc.a"},"children":[{"value":{"forumCategoryId":2,"nameKey":"a","descriptionKey":"b"},"children":[],"height":1}],"height":2}

问题是我的浏览器中没有显示任何内容。从普通 POJO 接收 json 就像一个魅力。我唯一的问题是从返回 Tree<?> 数据的休息服务中得到答案。

编辑:

我尝试使用 POSTMAN REST 客户端,但失败并显示以下消息:

响应状态为 0。查看 W3C XMLHttpRequest Level 2 规范以了解有关何时发生这种情况的更多详细信息。

W3C 规范说:

status 属性必须返回运行这些步骤的结果:

如果状态为 UNSENT 或 OPENED,则返回 0 并终止这些步骤。

如果设置了错误标志,则返回 0 并终止这些步骤。

返回 HTTP 状态码。

4

1 回答 1

0

我想到了。

首先,我尝试从 getSize 中返回 0 ..

然后我可能通过使用 string.length() * Character.SIZE / Byte.SIZE 错误地计算了长度。

然后我尝试从getSize返回-1,这使得jersey-json自己计算长度。

于 2013-10-17T12:14:19.390 回答