Lançar exceção entre camadas

Pessoal, to com o seguinte problema:

Tenho que lançar uma exceção (própria) entre três módulos, em camadas diferentes, assim:

Camada de Infra - UsuarioDAOJdbc ( onde a excessão pode ocorrer )

	public Usuario obterUsuarioPorUsername(String username) throws DAOException{
		Usuario usuario = null;
		String sql = "select * from usuario where login = ?";
		PreparedStatement st = null;
		ResultSet rs = null;
		Connection con = DBUtil.getInstance().getConnection();
		try {
			st = con.prepareStatement(sql);
			st.setString(1, username);
			rs = st.executeQuery();
			if (rs.next()) {
				String nome = "";
				String user = "";
				String senha = "";
				usuario= new Usuario(nome,user,senha);
				usuario.setNome(rs.getString("nome"));
				usuario.setUsername(rs.getString("login"));
				usuario.setPassword(rs.getString("senha"));
			}
		} catch (SQLException ex) {
			throw new DAOException(ex);
		} finally {
			try {
				con.close();
				DBUtil.getInstance().limpaCon();
			} catch (SQLException e) {
				throw new DAOException(ex);
			}
		}
		return usuario;		
	}

Camada de Domínio - UsuarioRepositório (a “ponte” entre a camada da aplicação e a de infra)

public class UsuarioRepositorio {

	private IUsuarioDAO usuarioDao = new UsuarioDAOJdbc();


	public Usuario obterUsuarioPorUsername(String username) throws RepositorioException
	{
		return usuarioDao.obterUsuarioPorUsername(username);
	}
	
}

Camada de aplicação- UsuarioRepositório (a “ponte” entre a camada da aplicação e a de infra)


                                ...
		UsuarioRepositorio ur = new UsuarioRepositorio();
		
		try {

			Usuario usuario = ur.obterUsuarioPorUsername(username);
			
			if (usuario == null) {
				return "/login.jsp?mensagem=Acesso Restrito";
			} else {
				System.out.println("Menu!!!!");
				request.getSession().setAttribute("username", username);
				return "/menu.jsp";
			}
                                 // Onde a exceção deve ser tratada
		} catch (RepositorioException e) {
			String message = "Houve um erro.";
			return "/login.jsp?mensagem=Deu problema de excessão !!!!";
		}
	}

A questão é: Como “escrevo” as classes DAOException e RepositorioException , afim de que lançem a exceção desde a camada de DAO (usando DAOException) até a camada da aplicação (usando RepositorioException) ?

Anida não consegui compreender bem esse esquema de “lançar” exceções para uma outra classe “tratar”.

Agradeço qualquer ajuda

Grande abraço a todos
Fábio

Bom dia.

O ideial seria criar uma classe abstrata (classe pai) que extenda Exception. A partir dai, você cria suas classes extendendo da classe abstrata e que lança um determinado tipo de excessão. Mas se o seu problema está em lidar com Exception, use as que o próprio Java possiu. Um exemplo simples é você utilizar Exception em um determinado método, exemplo, método Inserir.

A partir do seu DAO, que seria a camada de nível mais baixo, você já faz esse tratamento, assim:

public void Inserir throws Exception{ //seu código }

Quando usar o delegate para chamar este método obrigatoriamente terá que existir throws Exception e obriga você a usar try-catch ou throws mesmo no seu Servlet, se ocorrer uma excessão no seu DAO ele vai lançar essa excessão até a sua camada de mais alto nível, ai depois a questão é como você vai tratar isso :slight_smile:

Abraços.

Vc está no bom caminho.
Vc já tem a estrutrua necessária.
A sua DAOException recebe uma SQLException no construtor.
Só precisa que a sua RepositorioException tb receba Exception no construtor.
Você pode criar uma filha de RepositorioException chamada DataAccessRepositoryException para marcar que é uma exceção de acesso aos dados. Mas isso fica a seu critério. A unica laterção que precisa fazer no seu codigo é:

[code]public Usuario obterUsuarioPorUsername(String username) throws RepositorioException
{
try{
return usuarioDao.obterUsuarioPorUsername(username);
} catch (Exception e){
return new RepositorioException (e);
}
}

[/code]

No meu caso eu criei uma extrutura muito semelhante. Eu não tenho DAOs porque uso JPA, então apenas repositórios e os EJBs acessando esses repositórios. E ao invés de trabalhar com Exception tenho usado RuntimeException. Na camada web possui um exception-handlers que trata as exceptions.

abstract class AbstractApplicationException extends RuntimeException; - classe abstrata que todas herdam

public class InfraestructureException extends AbstractApplicationException; - erros de infra

public class RepositoryException extends AbstractApplicationException; - erros na camada repository

public class ServiceException extends AbstractApplicationException; - erros de regra de negócio

Pessoal
Obg pelas respostas.

Eu já até tinha feito umas classes baseadas em exception (DAOException e RepositorioException) , mas não
consegui “repassar” a exceção do DAO para o Repositorio , e deste para o Servlet que esta na camada
mais “alta”.

Não deveria seria assim: ( sou newbie msmo em exceções - e ainda em mta coisa em java )

Classe DAOException

[code]public class DAOException extends Exception {

public DAOException(Exception e) throws RepositorioException 
{
	throw new RepositorioException(e);
}

}[/code]

Classe RepositorioException

[code]public class RepositorioException extends Exception {

public RepositorioException(Throwable cause) 
{
	cause.printStackTrace();
}

}[/code]

Vou tentar essas dicas de vcs sobre criar uma abstrata na qual as especificas se baseiam.

Abraço a todos.

[code]
public class RepositorioException extends Exception {

public RepositorioException(Throwable cause) 
{
	super(cause);
}

}[/code]

assmi vc consegue ir rastreando a exceção.

[quote=fabiogm]Pessoal
Obg pelas respostas.

Eu já até tinha feito umas classes baseadas em exception (DAOException e RepositorioException) , mas não
consegui “repassar” a exceção do DAO para o Repositorio , e deste para o Servlet que esta na camada
mais “alta”.

Não deveria seria assim: ( sou newbie msmo em exceções - e ainda em mta coisa em java )
[/quote]

Então parabéns, porque seu codigo é melhor estruturado que muito codigo java que já vi por ai de pessoas que não se dizem newbies.

Veja bem, uma Exception é uma classe como qualquer outra.
Porquê o construtor da DAOException deveria lançar RepositorioException ?
Além disso ser uma violação das camadas ( o que já deveria ser um alerta) não faz sentido já que é impossivel criar um objeto da classe DAOException. Outra regra que vc está violando aqui é lançar exception no construtor. Embora possivel, isso é indicativo que ha algum problema com o design da sua classe.

Como o mario.fts já falou basta chamar o construtor da classe mãe através de super() Repare como o código correto não lança exceções no construtor, não usa throw no corpo do construtor e não viola camadas.

Sérgio, mas nesses casos como o do colega, o mais correto é ver as exceptions como as dele filhas de exception ou de runtime?

Pessoal, muito obrigado pela ajuda. Agora estou no trampo , mas assim q chegar em casa vou tentar aplicar as dicas de vocês.

Obg msmo

Abraço a todos

Fábio

As exceções que advém de comunicação com outros sistemas tendem a ser verificadas. Neste caso as DAOException seriam verificadas, filhas de Exception.
As de repositório podem ser não verificadas já que o repositório não comunica diretamente com outros sistemas. Estas seria filhas de RuntimeException.

Uma outra forma de analisar é pensar que repositórios estão na layer de dominio, enquanto que DAO na de integração que está abaixo da de dominio. São layers diferentes e isso tem implicações na hierarquia de exceções.

O padrão Layer SuperType - em que ha um tipo master para a layer - tb se aplica a exceptions (aliás é essencial ser aplicado a exceptions) por isso cada layer deve ter um tipo de exceção que derive diretamente das exceções do java padrão. Ter um abstractException para todas as exceções do sistema não é boa prática porque fere uma das diretivas ao criar exceções : ser especifico.

Usar exceções verificadas é opcional em Java, vc pode sempre declarar como filha de runtime e escrever seu codigo sem problemas, contudo se vc seguir a regra de que camadas que comunicam com outros sistemas lançam exceções verificadas vc terá um controle melhor porque esse tipo de tratamento é feito apenas na fronteira das camadas e não polui o resto do sistema com tratamento redundante. O exemplo de encapsular DAOException em RepositoryException mostra isto claramente. Se DAOException for verificada o uso de try-catch para encapsular é obrigatório já que o Repositorio recebe essa exceçõa , mas não a pode declarar no throws do método. Isto leva a um otimo controle do fluxo de exceções e a uma boa programação.

Sérgio, muito obrigado. Vou rever então meu conceito quando a herdar uma abstract-exception.

Complementando, há um tópico muito bom sobre checked e unchecked exceptions: http://guj.com.br/posts/list/116363.java