Solucionado (ver solução)
Solucionado
(ver solução)
6
respostas

A Variavel DATABASE_URL vem nula e da o erro Application error ao tentar acessar no heroku

A Variavel DATABASE_URL vem nula e da o erro Application error ao tentar acessar no heroku

6 respostas
2019-06-30T22:50:55.331997+00:00 app[web.1]: Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.jdbc.datasource.DriverManagerDataSource]: Factory method 'dataSource' threw exception; nested exception is java.lang.NullPointerException
2019-06-30T22:50:55.331999+00:00 app[web.1]: at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
2019-06-30T22:50:55.332001+00:00 app[web.1]: at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
2019-06-30T22:50:55.332003+00:00 app[web.1]: ... 53 more
2019-06-30T22:50:55.332005+00:00 app[web.1]: Caused by: java.lang.NullPointerException
2019-06-30T22:50:55.332007+00:00 app[web.1]: at java.net.URI$Parser.parse(URI.java:3042)
2019-06-30T22:50:55.332009+00:00 app[web.1]: at java.net.URI.<init>(URI.java:588)
2019-06-30T22:50:55.332011+00:00 app[web.1]: at br.com.casadocodigo.loja.config.JPAProductionConfiguration.dataSource(JPAProductionConfiguration.java:39)
2019-06-30T22:50:55.332013+00:00 app[web.1]: at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
2019-06-30T22:50:55.332015+00:00 app[web.1]: at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
2019-06-30T22:50:55.332017+00:00 app[web.1]: at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
2019-06-30T22:50:55.332024+00:00 app[web.1]: at java.lang.reflect.Method.invoke(Method.java:498)
2019-06-30T22:50:55.332026+00:00 app[web.1]: at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
2019-06-30T22:50:55.332028+00:00 app[web.1]: ... 54 more
package br.com.casadocodigo.loja.config;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Properties;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Profile;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@EnableTransactionManagement
@Profile("prod") 
public class JPAProductionConfiguration {

    @Autowired
    private Environment environment;

    @Bean
    public Properties additionalProperties() {
        Properties properties = new Properties();
        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
        properties.setProperty("hibernate.show_sql", "true");
        properties.setProperty("hibernate.hbm2ddl.auto", "update");
        return properties;
    }

    @Bean
    private DriverManagerDataSource dataSource() throws URISyntaxException {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("org.postgresql.Driver");

        String getenv = System.getenv("DATABASE_URL");
        System.out.println("Variavel: DATABASE_URL " + getenv);
        URI dbUrl = new URI(environment.getProperty("DATABASE_URL"));

        dataSource.setUrl("jdbc:postgresql://"+dbUrl.getHost()+":"+dbUrl.getPort()+dbUrl.getPath());
        dataSource.setUsername(dbUrl.getUserInfo().split(":")[0]);
        dataSource.setPassword(dbUrl.getUserInfo().split(":")[1]);

        return dataSource;
    }


}
package br.com.casadocodigo.loja.config;

import javax.servlet.Filter;
import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;

import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter;
import org.springframework.web.context.request.RequestContextListener;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;


//Classe de servlet do spring
public class ServeletSpringMvc extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        //Sobe a configuração de segurança quando o sistema subir
        return new Class[] {SecurityConfiguration.class, AppWebConfiguration.class, JPAConfiguration.class, JPAProductionConfiguration.class}; ///por conta do login, tem que passar o JPa para ca
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
//        return new Class[] {AppWebConfiguration.class, JPAConfiguration.class}; //Mapeia a classe de configurações
        return new Class[] {};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] {"/"}; //significa que sera a raiz para o sistema atender
    }

    @Override //adiciona um filter para alterar o encoding
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("UTF-8");
        //Há um filtro pronto especifico para a solução deste problema chamado OpenEntityManagerInViewFilter.
//        Com este filtro configurado, podemos remover o join adicionado anteriormente e ver que a listagem continua funcionado.
//        Mas cuidado, o uso do Lazy Inicialization que faz esse carregamento tardio dos recursos pode nos trazer problemas, com muitos selects
        return new Filter[] {characterEncodingFilter, new OpenEntityManagerInViewFilter()};
    }

    //Configuração para o arquivo Multipart
    @Override
    protected void customizeRegistration(Dynamic registration) {
        registration.setMultipartConfig(new MultipartConfigElement(""));
    }

    //PARA USAR O HEROKU, DEVE COMENTAT AQUI, PARA MUDAR O PROFILE DE INICIALIZAÇÃO
    //Configuração para adicionar o profile de qual banco de dados que ficará ativo ao startar o servidor
//    @Override
//    public void onStartup(ServletContext servletContext) throws ServletException {
//        super.onStartup(servletContext);
//        servletContext.addListener(RequestContextListener.class);
//        servletContext.setInitParameter("spring.profiles.active", "dev");
//    }



}

O painel do Heroku: https://imge.to/i/jgL9H

Se alguem puder ajudar agradeço.

No Heroku você está passando as variáveis conforme tutorial: https://devcenter.heroku.com/articles/config-vars

?

Ola Otavio, Na aula nao informa sobre essas configurações, apenas diz o trecho abaixo::

"Uma observação a ser feita é que no Heroku não temos o controle sobre os dados de acesso ao banco de dados. Estes dados são disponibilizados através de variaveis de ambiente. Estas podem ser acessadas através de um atributo inicializado pelo próprio Spring, chamado de Environment.

Através deste objeto Environment podemos usar o método getProperty que retorna uma propriedade deste objeto. A propriedade que queremos pode ser acessada passando o valor DATABASE_URL para este método. Que retornara uma String no seguinte formato:

usuario:senha@host:port/path

A String retornada segue um padrão bem conhecido chamado de URI. Para que não precisemos manipular Strings para extrair cada uma das informações requeridas. Criaremos um objeto do tipo URI que já nos fornece método mais fáceis de extrair estes dados a partir da String"
solução!

SOLUÇÃO: Para funcionar é necessário adicionar o addons ao seu APP no Heroku, acessando o link https://elements.heroku.com/addons/heroku-postgresql