Solucionado (ver solução)

Importante

Você está vendo a versão anterior da nova experiência da Alura que estamos preparando para você. Em breve, ela ganha uma identidade visual novinha totalmente pensada em potencializar seus estudos!

Solucionado
(ver solução)
17
respostas

Dúvida em relação à dependências

Bom dia,

Eu tenho uma aplicação desktop pronta em Java Swing e Hibernate e gostaria de implementar alguns serviços REST sem mudar a estrutura do projeto para um WebApp, usando apenas Jersey e Grizzly. Eu simplesmente criei um pacote resources para os meus recursos JAX-RS. As entidades estão todas marcadas com @XmlRootElement.

No exemplo do curso eu deletei as pastas usadas em projeto web(webapp, web-inf, web.xml), importei as libs do projeto pelo Eclipse e deu certo...consegui testar os serviços sem web.xml, e etc...só que o projeto do curso não usa maven e já vem com todas as dependências "de mão beijada" e estou tendo dificuldades na escolha das dependências corretas...Quando eu acesso a url abaixo eu tenho erro 500...Eu queria gerar o xml usando jaxb...

http://localhost:8081/exemplo/categorias/1

Eu adicionei essas quatro dependências no meu pom.xml

    <dependency>
            <groupId>org.glassfish.grizzly</groupId>
            <artifactId>grizzly-http-server</artifactId>
            <version>2.4.0</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-grizzly2-http</artifactId>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.inject</groupId>
            <artifactId>jersey-hk2</artifactId>
        </dependency>

Minha classe de servidor:

package com.exemplo;

import java.io.IOException;
import java.net.URI;

import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;

import com.floreantpos.model.dao.MenuCategoryDAO;
import com.floreantpos.util.DatabaseUtil;

public class GrizzlyServer {

    public static final String BASE_URI = "http://localhost:8081/exemplo/";

    public static HttpServer startServer() {

        final ResourceConfig rc = new ResourceConfig().packages("com.floreantpos");
        return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
    }

    public static void main(String[] args) throws IOException {

        final HttpServer server = startServer();
        System.out.println(String.format("Servidor Grizzly inicializado", BASE_URI));
        System.in.read();
        server.stop();
    }

}

Meu recurso:

package com.exemplo.resources;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.exemplo.model.MenuCategory;
import com.exemplo.model.dao.MenuCategoryDAO;

@Path("categorias")
public class MenuCategoryResource {

    @GET
    @Path("{id}")
    @Produces(MediaType.APPLICATION_XML)
    public MenuCategory busca(@PathParam("id") int id) {
        MenuCategoryDAO categoryDao = new MenuCategoryDAO().getInstance();
        return categoryDao.get(id);
    }

}

Entidade:

package com.exemplo.model;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

import org.apache.commons.lang.StringUtils;

@XmlRootElement(name = "menu-category")
@XmlAccessorType(XmlAccessType.FIELD)
public class MenuCategory extends BaseMenuCategory {
    private static final long serialVersionUID = 1L;


    public MenuCategory () {
    }
...
17 respostas

Olá, Fernando.

Qual é o stack trace do erro?

Olá Alexandre,

No console do eclipse não aparece nenhum erro, apenas no browser aparece :

Esta página não está funcionando localhost não consegue atender a esta solicitação no momento. HTTP ERROR 500

Seria legal você debugar, colocando alguns breakpoints pra descobrir qual é o ponto de falha!

Dá pra tentar habilitar o log do Grizzly também:

Logger l = Logger.getLogger("org.glassfish.grizzly.http.server.HttpHandler");
l.setLevel(Level.FINE);
l.setUseParentHandlers(false);
ConsoleHandler ch = new ConsoleHandler();
ch.setLevel(Level.ALL);
l.addHandler(ch);

Os imports são todos do pacote java.util.logging.*

Alexandre eu tive que mudar o nível do log para Level.ALL para ter alguma saída no console e obtive o seguinte log nesse link https://gist.github.com/fernandocorrea/5655e43e96a3cc7100eba04e76e29f23#file-saida-grizzly

Me parece que foi gerado pela linha abaixo mas eu não consigo identificar aonde eu errei

final ResourceConfig rc = new ResourceConfig().packages("com.exemplo");

Fernando,

pode ignorar esse erro de inicialização.

O que ocorre quando você faz um requisição?

Alexandre segue link do log gerado quando eu acesso http://localhost:8081/exemplo/categorias/1

https://pastebin.com/XbtqjsQ5

solução!

Veja que foi um erro no JAXB, na transformação de objetos para XML, por causa de um ciclo:

Caused by: javax.xml.bind.MarshalException
 - with linked exception:
[com.sun.istack.internal.SAXException2: Foi detectado um ciclo no gráfico do objeto. Isso causará XML profundo infinitamente: APPETIZERS -> FRENCH FRIES -> APPETIZERS]

APPETIZERS tem FRENCH FRIES que tem APPETIZERS

O lance é quebrar esse ciclo dos objetos!

Não entendi bem Alexandre...

No meu banco FRENCH FRIES é um APPETIZERS. FRENCH FRIES é uma linha na tabela menu_group, e essa tabela possui um campo category_id que é o id da categoria que no caso é o id do APPETIZER.

veja o link sobre como está o relacionamento das tabelas: https://imgur.com/a/R8bJb

Eu preciso mudar minha classe de entidade?

Como está o modelo dos objetos?

Vi um trecho classe MenuCategory, mas ela deve depender de MenuGroup.

Agora, a classe MenuGroup tem algum atributo do tipo MenuCategory?

package com.example.model;

import java.awt.Color;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

import org.apache.commons.lang.StringUtils;

import com.example.config.TerminalConfig;
import com.example.model.base.BaseMenuCategory;

@XmlRootElement(name = "menu-category")
@XmlAccessorType(XmlAccessType.FIELD)
public class MenuCategory extends BaseMenuCategory {
    private static final long serialVersionUID = 1L;

    public MenuCategory () {
        //super();
    }

    public MenuCategory (java.lang.Integer id) {
        super(id);
    }

    public MenuCategory (
        java.lang.Integer id,
        java.lang.String name) {
        super (id, name);
    }

    private Color buttonColor;
    private Color textColor;

    @Override
    public Integer getSortOrder() {
        return sortOrder == null ? 9999 : sortOrder;
    }

    @XmlTransient
    public Color getButtonColor() {
        if (buttonColor != null) {
            return buttonColor;
        }

        if (getButtonColorCode() == null || getButtonColorCode() == 0) {
            return null;
        }

        return buttonColor = new Color(getButtonColorCode());
    }

    public void setButtonColor(Color buttonColor) {
        this.buttonColor = buttonColor;
    }

    @XmlTransient
    public Color getTextColor() {
        if (textColor != null) {
            return textColor;
        }

        if (getTextColorCode() == null || getTextColorCode() == 0) {
            return null;
        }

        return textColor = new Color(getTextColorCode());
    }

    public void setTextColor(Color textColor) {
        this.textColor = textColor;
    }

    public String getDisplayName() {
        if (TerminalConfig.isUseTranslatedName() && StringUtils.isNotEmpty(getTranslatedName())) {
            return getTranslatedName();
        }

        return super.getName();
    }

    @Override
    public String toString() {
        return getDisplayName();
    }

    public String getUniqueId() {
        return ("menu_category_" + getName() + "_" + getId()).replaceAll("\\s+", "_"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
    }
}
package com.exemplo.model.base;

import java.io.Serializable;


public abstract class BaseMenuCategory  implements Comparable, Serializable {

    public static String REF = "MenuCategory";
    public static String PROP_NAME = "name";
    public static String PROP_TEXT_COLOR_CODE = "textColorCode";
    public static String PROP_BEVERAGE = "beverage";
    public static String PROP_VISIBLE = "visible";
    public static String PROP_SORT_ORDER = "sortOrder";
    public static String PROP_BUTTON_COLOR_CODE = "buttonColorCode";
    public static String PROP_ID = "id";
    public static String PROP_TRANSLATED_NAME = "translatedName";

    public BaseMenuCategory () {
        initialize();
    }

    public BaseMenuCategory (java.lang.Integer id) {
        this.setId(id);
        initialize();
    }

    public BaseMenuCategory (
        java.lang.Integer id,
        java.lang.String name) {

        this.setId(id);
        this.setName(name);
        initialize();
    }

    protected void initialize () {}

    private int hashCode = Integer.MIN_VALUE;

    private java.lang.Integer id;

    protected java.lang.String name;
    protected java.lang.String translatedName;
    protected java.lang.Boolean visible;
    protected java.lang.Boolean beverage;
    protected java.lang.Integer sortOrder;
    protected java.lang.Integer buttonColorCode;
    protected java.lang.Integer textColorCode;

    private java.util.List<com.exemplo.model.Discount> discounts;
    private java.util.List<com.exemplo.model.MenuGroup> menuGroups;

    public java.lang.Integer getId () {
        return id;
    }


    public void setId (java.lang.Integer id) {
        this.id = id;
        this.hashCode = Integer.MIN_VALUE;
    }

    public java.lang.String getName () {
        return name;
    }

    public void setName (java.lang.String name) {
        this.name = name;
    }

    public java.lang.String getTranslatedName () {
        return translatedName;
    }

    public void setTranslatedName (java.lang.String translatedName) {
        this.translatedName = translatedName;
    }

    public java.lang.Boolean isVisible () {
        return visible == null ? Boolean.FALSE : visible;
    }

    public void setVisible (java.lang.Boolean visible) {
        this.visible = visible;
    }

    public java.lang.Boolean isBeverage () {
        return beverage == null ? Boolean.FALSE : beverage;
    }

    public void setBeverage (java.lang.Boolean beverage) {
        this.beverage = beverage;
    }

    public java.lang.Integer getSortOrder () {
        return sortOrder == null ? Integer.valueOf(0) : sortOrder;
    }

    public void setSortOrder (java.lang.Integer sortOrder) {
        this.sortOrder = sortOrder;
    }

    public java.lang.Integer getButtonColorCode () {
        return buttonColorCode == null ? Integer.valueOf(0) : buttonColorCode;
    }

    public void setButtonColorCode (java.lang.Integer buttonColorCode) {
        this.buttonColorCode = buttonColorCode;
    }


    public java.lang.Integer getTextColorCode () {
        return textColorCode == null ? Integer.valueOf(0) : textColorCode;
    }

    public void setTextColorCode (java.lang.Integer textColorCode) {
        this.textColorCode = textColorCode;
    }

    public java.util.List<com.exemplo.model.Discount> getDiscounts () {
        return discounts;
    }

    public void setDiscounts (java.util.List<com.exemplo.model.Discount> discounts) {
        this.discounts = discounts;
    }

    public void addTodiscounts (com.exemplo.model.Discount discount) {
        if (null == getDiscounts()) setDiscounts(new java.util.ArrayList<com.exemplo.model.Discount>());
        getDiscounts().add(discount);
    }

    public java.util.List<com.exemplo.model.MenuGroup> getMenuGroups () {
        return menuGroups;
    }

    public void setMenuGroups (java.util.List<com.exemplo.model.MenuGroup> menuGroups) {
        this.menuGroups = menuGroups;
    }

    public void addTomenuGroups (com.exemplo.model.MenuGroup menuGroup) {
        if (null == getMenuGroups()) setMenuGroups(new java.util.ArrayList<com.exemplo.model.MenuGroup>());
        getMenuGroups().add(menuGroup);
    }

    public boolean equals (Object obj) {
        if (null == obj) return false;
        if (!(obj instanceof com.exemplo.model.MenuCategory)) return false;
        else {
            com.exemplo.model.MenuCategory menuCategory = (com.exemplo.model.MenuCategory) obj;
            if (null == this.getId() || null == menuCategory.getId()) return false;
            else return (this.getId().equals(menuCategory.getId()));
        }
    }

    public int hashCode () {
        if (Integer.MIN_VALUE == this.hashCode) {
            if (null == this.getId()) return super.hashCode();
            else {
                String hashStr = this.getClass().getName() + ":" + this.getId().hashCode();
                this.hashCode = hashStr.hashCode();
            }
        }
        return this.hashCode;
    }

    public int compareTo (Object obj) {
        if (obj.hashCode() > hashCode()) return 1;
        else if (obj.hashCode() < hashCode()) return -1;
        else return 0;
    }

    public String toString () {
        return super.toString();
    }

}

Acredito que o problema esteja na lista de MenuGroups que a classe mãe da minha entidade possui:

private java.util.List<com.floreantpos.model.MenuGroup> menuGroups;

Você concorda Alexandre? Se eu retirar essa linha eu posso alterar algum outro fluxo do sistema....tem como configurar esse detalhe no jaxb?

Creio que é por aí mesmo!

Você pode omitir um objeto do XML com a anotação @XmlTransient.

Mas minha classe pai não é anotada com @XmlRootElement.... existe alguma peculiaridade no mapeamento de classes que herdam de outras no jaxb?

Boa pergunta, Fernando! Nunca enfrentei esse caso!

Ok Alexandre,

Eu testei em uma entidade simples sem relacionamentos e deu certo...como estou iniciando em JAX-RS e nunca havia trabalhado com JAXB acho que esse teste foi suficiente para saber o que "me aguarda".

Vou estudar melhor o mapeamento desses relacionamentos...Eu não queria alterar as entidades porque já estão prontas e funcionando... mas vou estudar e ver o que pode ser feito.

Obrigado pela ajuda

Bacana, Fernando!

Ninguém disse que ia ser fácil! hehe

Bons estudos e bom trabalho!