Jboss Seam

Por curiosidade, dei uma espiada no Seam, e muito me interessou o que vi. Mas como sempre, quando usamos efetivamente um framework é que percebemos as suas deficiências.

Alguém que está usando/já usou ele por mais tempo, poderia citar algumas das deficiências e claro, quais as grandes vantagens que viu/está vendo nele?

Rapaz, “grandes vantagens” são o que eles vendem mesmo. A diminuição absurda da quantidade de configuração e os conversations (ligados diretamente a transações EJB).

Eu resto eu achei firula, mas só esses dois features já são mais do que o suficiente pra usar.

O maior problema que eu achei foi a dificuldade de fazer o microkernel rodar no Jetty (na verdade, não consegui fazer ele rodar) e ter que empacotar a parte “EJB” da aplicação em modo separado, isso realmetne complicou um bocado o modo como eu trabalho (que é desenvolver no Maven 2/Jetty e implantar num Jetty).

Acho que melhorando esse negócio de fazero bixo executar, o resto é besteira, vale muito a pena usar, maaaaassssssssss, se o Spring-Annotations do Urubatan caminhar mesmo, acho que o Seam vai ter sérios problemas :smiley:

[quote=Maurício Linhares]
Acho que melhorando esse negócio de fazero bixo executar, o resto é besteira, vale muito a pena usar, maaaaassssssssss, se o Spring-Annotations do Urubatan caminhar mesmo, acho que o Seam vai ter sérios problemas :D[/quote]
Annotation para wiring de componentes??? Naooooooo!:shock:
Para onde vai o DI (Dependency Injection) nessa história toda? Dependency Lookup (Service Locator) no Spring naoooooooooo!! :shock:

Meus comentários no fórum sobre esse assunto:
http://www.guj.com.br/posts/list/39153.java#209565
http://www.guj.com.br/posts/list/39520.java

No fórum do Spring:

Artigo sobre IoC e DI do Martin Fowler:

Sou a favor do uso de Java Annotation sim, mas não para wiring! Isso, na minha opinião (e, pelo que tenho observado, de muitos que realmente sabem o que estão falando no fórum do Spring), quebra a DI.
É preciso tomar cuidado de não esquecer que um dos conceitos mais importantes e inovadores desses lightweight frameworks como o Spring é a Dependency Injection (embora quase ninguem saiba direito o que isso significa, muito menos a diferença com Dependency Lookup, e ainda assim acha o Spring o máximo! :cry: ).
A grande idéia que existe por trás deste conceito é o fato do componente ser passivo, isto é, o componente não corre atrás da implementação de suas dependências (aliás, ele nem sabe quem são elas; o componente conhece apenas as interfaces delas, seguindo o velho princípio “Program to Interfaces, not to Implementations”). Assim, existe um assembler (que é aonde o Spring/IoC Container entra em cena) que faz o wiring dessas dependências no seu componente usando um dos mecanismos de Injeção de Dependência (DI). Observe que o componente não precisa conhecer (leia-se “depender de”) o assembler, já que a “mágica” acontece através de simples Setters/Constructors (ou interface, no caso do Avalon). E é exatamente essa a diferença com um Service Locator ou uma Factory, onde o seu componente acaba criando uma nova dependência com esses “terceiros” para solicitar sua própria dependência… ! Isso é Dependency Lookup (Service Locator), e não Dependency Injection. E, o Spring, segue a linha de um framework totalmente baseado em DI.

Rapaz, gosto é gosto.

Configuração em annotations não quebra a injeção de dependências simplesmente porque o objeto que tem a annotation continua sem saber qual a sua dependência. É simplesmente uma mudança de lugar de uma configuração que existiria de qualquer forma em outra parte do código (o arquivo XML do Spring).

Direto do tutorial do JBoss Seam, no capítulo 1, tem o annotation @Name e @Scope, veja:

@Entity @Name("user") @Scope(SESSION) @Table(name="users") public class User implements Serializable {

eu achei um tanto esquisito dizer ao entity qual é o escopo e o seu nome, além de que que o valor “user” na annotation @Name é utilizado para DI. Ou seja, ao meu ver, o código sabe detalhes sobre a injeção de dependência. Essa foi uma má impressão que tive do framework, mas ainda não comecei a estudar ele pra valer, mas acho que já seria bom começar a discutir sobre os prós e contras do framework.

Quais detalhes? Um String? Isso é realmente um detalhe?

Não estou vendo nenhuma informação que não seja da própria classe aí.

bom, então …

[code]@Stateless
@Name(“register”)
public class RegisterAction implements Register
{

@In
private User user;[/code]

Quanto a annotation @In, o tutorial diz:

[quote=Chapter1. Seam Tutorial]
The @In annotation marks an attribute of the bean as injected by Seam. In this case, the attribute is injected from a context variable named user (the instance variable name).[/quote]

Posso até estar errado, mas acho que a string “user” usado na annotation @Name do entity é uma condição para que a annotation @In funcione. Por isso não acho que a informação @Name(“user”) pertença a classe User. Se eu estiver, errado, me corrija.

Como não conheço ainda o framework, fico me perguntando o que fazer se precisarem do entity User em algum outro escopo da aplicação, ou se por exemplo, precisar de 2 nomes. Por exemplo: @Name({“user1”, “user2”}).

Se existe a necessidade de um mesmo objeto estar disponível em vários escopos diferentes da aplicação, ele provavelmente só deveria estar no escopo mais abrangente e não nos menos abrangentes.

A anotação @Name é a anotação que define um nome lógico para um objeto (ou classe) em uma aplicação e a anotação @In apenas se utiliza desse nome lógico para injetar a dependência, assim como acontece em qualquer outro framework de injeção de dependências.

O tipo ou como a dependência chega a classe continua sendo invísível para o código que as usa e esse é o princípio da inversão de controle.

humm, então acho que entendi. Valeu!

E quanto ao fato do JBoss Seam usar os sessions beans como JSF Action Listeners? Sei que isso não é obrigatório, mas o que vocês acham desta abordagem?

É por isso que eu estou apostando no Spring-Annotations =D

Conseguir as mesmas funcionaldiades de Session Beans fora de um servidor de aplicações é tudo o que eu queria :smiley:

também acho que annotations quebra o DI, pelo principal fato que toda modificação de algo anotado precisa ser recompilado, ao contrário do DI que usa XML (vide Spring da vida)

annotations acho muito legal, evita escrever um monte de “pocaria”, faz a gente focar bastante na função principal do sistema e não ficar configurando deus e o mundo pra ter um componente de nada no AppServer. No caso de DI com annotations e wiring, acaba fazendo um código muito “colado e dependente”, meio que dando de cara com o objetivo principal de DI :stuck_out_tongue:

Acho que voces estao exagerando, que que tem a ver recompilar a classe ? vc tem que fazer deploy do projeto de qualquer forma… em dias de ant e de maven… “eu nao uso prq tenho que recompilar a classe” eh a desculpa mais esfarrapada que eu já vi.

O tópico está meio parado, mas vamos reanimá-lo.

Estou tentando criar minha primeira aplicação usando o Seam (1.2.1GA) porém estou com alguns problemas.

O ambiente é o Tomcat 5.5.20, o banco de dados é o MySQL 5.0.24a.
Estou usando o JBoss Microcontainer.

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>



org.hibernate.ejb.HibernatePersistence
java:/lojinhaDatasource








jboss-beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<bean name="lojinhaDatasourceBootstrap" class="org.jboss.resource.adapter.jdbc.local.LocalTxDataSource">
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="connectionURL">jdbc:mysql://localhost:3306/lojinha</property>
    <property name="userName">lojinha</property>
    <property name="password">lojinha</property>
    <property name="jndiName">java:/lojinhaDatasource</property>
    <property name="minSize">0</property>
    <property name="maxSize">10</property>
    <property name="blockingTimeout">1000</property>
    <property name="idleTimeout">100000</property>
    <property name="transactionManager"><inject bean="TransactionManager"/></property>
    <property name="cachedConnectionManager"><inject bean="CachedConnectionManager"/></property>
    <property name="initialContextProperties"><inject bean="InitialContextProperties"/></property>
</bean>

<bean name="lojinhaDatasource" class="java.lang.Object">
    <constructor factoryMethod="getDatasource">
        <factory bean="lojinhaDatasourceBootstrap"/>
    </constructor>
</bean>

O fonte das entidades:

@MappedSuperclass
public class SuperEntidade implements Serializable {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = “NCOD_ID”, nullable = false, insertable = false)
protected Long id;

@Entity
@Name(“contato”)
@AttributeOverride(name = “id”, column = @Column(name = “NCOD_ID”))
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = “TB_CT_CONTATO”)
public class Contato extends SuperEntidade {

public static final String[] TIPOS_CONTATOS = {"Pessoa física", "Pessoa Jurídica"};

@Column(name = "CNOM_NOME", nullable = false, length = 150)
@NotNull(message = "Valor requerido.")
protected String nome;

@Column(name = "CTXT_EMAIL", nullable = false, length = 220, unique = true)
@NotNull(message = "Valor requerido.") @Email(message = "O endereço de e-mail deve ser válido.")
protected String mail;

@Column(name = "CTXT_OBS", nullable = true, length = 1500, unique = false)
protected String observacoes;

@Column(name = "CTIP_TIPO_PESSOA", nullable = false, length = 1, unique = false)
@Length(min = 1, max = 1, message = "Tamanho máximo excedido.")
protected String tipo;

@Entity
@Name(“pessoa fisica”)
@AttributeOverride(name = “id”, column = @Column(name = “NCOD_ID_CONTATO”))
@PrimaryKeyJoinColumn(name = “NCOD_ID_CONTATO”)
@Table(name = “TB_CT_PESSOA_FISICA”)
public class PessoaFisica extends Contato {

@Column(name = "CNUM_CPF", nullable = false, length = 11, unique = true)
@NotNull(message = "Valor requerido.")
protected String cpf;

@Column(name = "CNUM_RG", nullable = true, length = 10, unique = false)
@NotNull(message = "Valor requerido.")
protected String rg;

@Temporal(TemporalType.DATE)
@Column(name = "DDAT_NASCIMENTO", nullable = false, unique = false)
@NotNull(message = "Valor requerido.")
protected Date dataNascimento;

@Entity
@Name(“credencial”)
@AttributeOverride(name = “id”, column = @Column(name = “NCOD_ID_PESSOA_FISICA”))
@PrimaryKeyJoinColumn(name = “NCOD_ID_PESSOA_FISICA”)
@Table(name = “TB_SG_CREDENCIAL”)
public class Credencial extends PessoaFisica {

@Column(name = "CTXT_SENHA", nullable = false, length = 64)
@NotNull(message = "Valor requerido.") @Length(min = 8, max = 100, message = "Tamanho deve estar entre 8 e 100 caracteres.")
protected String senha;

@Column(name = "DDAT_CADASTRO", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
protected Calendar dataCadastro;

@Column(name = "DDAT_MODIFICACAO", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
protected Calendar dataModificacao;

@Column(name = "CURL_AVATAR", nullable = true, length = 256)
protected String urlAvatar;

@Column(name = "NSTA_ADMINISTRADOR", nullable = false)
protected Boolean administrador;

@Column(name = "NSTA_STATUS", nullable = false)
protected Integer status;

o form

        	<h:form>
                	<table border="0">
                    	<tr>
                        	<td class="cntForm">#{messages.lblContactPFName}</td>
                        	<td class="cntForm">
                        		<h:inputText id="nome" required="true" value="#{credencial.nome}">
									<s:validate />
                        		</h:inputText> *
                        	</td>
                        	<td><h:message for="nome" styleClass="cntError" /></td>
                    	</tr>
                    	<tr>
                        	<td>#{messages.lblContactPFCPF}</td>
                        	<td>
                        		<h:inputText id="cpf" required="true" value="#{credential.cpf}">
									<s:validate />
                        		</h:inputText> *
                       		</td>
                        	<td><h:message for="cpf" styleClass="cntError" /></td>
                    	</tr>
                    	<tr>
                        	<td>#{messages.lblContactPFRG}</td>
                        	<td>
                        		<h:inputText id="rg" required="true" value="#{credential.rg}">
                        			<s:validate />
                        		</h:inputText> *
                       		</td>
                        	<td><h:message for="rg" styleClass="cntError" /></td>
                    	</tr>
                    	<tr>
                        	<td>#{messages.lblContactPFDtNascimento}</td>
                        	<td>
								<h:inputText id="dataNascimento" value="#{credential.dataNascimento}" required="true">
									<s:convertDateTime pattern="dd/MM/yyyy"/>
									<s:validate />
								</h:inputText>
								<s:selectDate for="dataNascimento" dateFormat="dd/MM/yyyy" startYear="1970">
									<h:graphicImage url="/img/dtpick.gif" style="margin-left:5px;cursor:pointer"/>
								</s:selectDate>
                        	 </td>
                        	<td><h:message for="dataNascimento" styleClass="cntError" /></td>
                    	</tr>
                	</table>

            	<ui:remove><h:commandButton action="prev" value="Voltar" /></ui:remove>
            	<h:commandButton action="next" value="Avançar" />
        	</h:form>

Os problemas:

Quando tento inserir dados nos campos e aperto avançar, dá os seguintes erros:

“cpf”: Ocorreu um erro de conversão. (model validation failed)
“rg”: Ocorreu um erro de conversão. (model validation failed)
model validation failed:null (para a data de nascimento)

O que pode estar ocasionando isso?

Não existem erros no console do Tomcat.
Já procurei na web e existem poucas referências sobre o erro para o Seam.

Já achei o erro!!!
Desculpem-me.

Cara, quanto anotação!!! Será que vale a pena misturar tudo isso numa única classe?

Eu particularmente acho que a única annotation que vc deve usar é a @Override. :slight_smile:

Não seria mais fácil definir assim:

DI = Auto-Wiring = interfaces

IoC = Component Injection = classes

O cara que precisa receber um componente, seja por DI ou IoC, precisa declará-lo como uma interface, a não ser que por alguma razão ela não seja uma interface.

Ter DI atrelado a uma classe concreta soa muito mal, ou seja, fazer algo assim seria muito esquisito:

di(“userDAO”, OracleUserDAO.class).source(“dao”);

Vai até funcionar mas se amanhã o cara trocar o IoC que está gerando o UserDAO para MySQLUserDAO.class, ele vai ter que mudar toda a configuração de DI também, ou seja, ao invés de auto-wiring, virou dependency lookup.

É isso?

[quote=saoj]Ter DI atrelado a uma classe concreta soa muito mal, ou seja, fazer algo assim seria muito esquisito:

di(“userDAO”, OracleUserDAO.class).source(“dao”);

Vai até funcionar mas se amanhã o cara trocar o IoC que está gerando o UserDAO para MySQLUserDAO.class, ele vai ter que mudar toda a configuração de DI também, ou seja, ao invés de auto-wiring, virou dependency lookup.

É isso?
[/quote]

Onde é que a DI do Seam é atrelada a uma classe concreta?

Se você quer mudar o “userDAO” pra o MySQLUserDao, é só chegar nele e fazer isso:

@Name("userDAO")
public class MySQLUserDao

Nenhum dos clientes do “userDAO” vão saber que ele mudou.

Pessoal, alguém sabe me dizer se as annotations que vão adicionar no Spring será a (Spring-Annotations) do Urubatan?

Bem, ate onde li a respeito de Jboss Seam. Ele permite vc usar tanto Anotações como XML.

Entao para aqueles que precisarem usar o poder do XML, para não precisar recompilar todo momento, fica tranquilo.

Sorte a todos.

Odeio escrever XML… por isso acho ele fantático…