Home > Enterprise >  Trouble with JPA repositories while running on heroku
Trouble with JPA repositories while running on heroku

Time:08-04

I'm trying to deploy a vaadin website on heroku, the website works well, but the REST api that I made with Spring JPA returns always empty list. When running on my computer it works perfectly. There is no errors in heroku's console. How should I patch that ?

The table class :

package fr.xibalba.axiumwebsite.api.tables;

import com.fasterxml.jackson.annotation.JsonBackReference;
import lombok.*;

import javax.persistence.*;
import java.util.List;

@Entity
@Table(name = "roles")
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
@EqualsAndHashCode
public class Role {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false, unique = true)
    Integer id;

    @Column(name = "name", nullable = false, unique = true)
    String name;

    @Column(name = "priority", nullable = false)
    int priority;

    @Column(name = "prefix")
    String prefix;

    @Column(name = "multiple_prefix", nullable = false)
    boolean multiple_prefix;

    @Column(name = "prefix_color", nullable = false)
    String prefix_color;

    @Column(name = "suffix")
    String suffix;

    @Column(name = "multiple_suffix", nullable = false)
    boolean multiple_suffix;

    @Column(name = "suffix_color", nullable = false)
    String suffix_color;

    @JsonBackReference
    @ManyToMany(mappedBy = "roles")
    List<Account> accounts;
}

The JPA repository :

package fr.xibalba.axiumwebsite.api.repositories;

import fr.xibalba.axiumwebsite.api.tables.Role;
import org.springframework.data.jpa.repository.JpaRepository;

public interface RoleRepository extends JpaRepository<Role, Integer> {

    Role findByName(String name);
}

The REST controller :

package fr.xibalba.axiumwebsite.api.controllers;

import fr.xibalba.axiumwebsite.api.repositories.RoleRepository;
import fr.xibalba.axiumwebsite.api.tables.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/api/roles")
public class RoleController {

    @Autowired
    private RoleRepository roleRepository;

    @RequestMapping("")
    public List<Role> infos(@RequestParam(value = "name", required = false) String name, @RequestParam(value = "id", required = false) Integer id) {

        System.out.println("name: "   name);

        if (name != null && roleRepository.findByName(name) != null) {

            System.out.println("role found");
            return List.of(roleRepository.findByName(name));
        } else if (id != null && roleRepository.findById(id).isPresent()) {

            System.out.println("role found");

            return List.of(roleRepository.findById(id).get());
        } else {

            System.out.println("role not found");

            return roleRepository.findAll();
        }
    }
}

My pom.xml :

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>fr.xibalba</groupId>
    <artifactId>AxiumWebsite</artifactId>
    <version>0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>AxiumWebsite</name>
    <description>AxiumWebsite</description>
    <properties>
        <java.version>18</java.version>
        <vaadin.version>23.1.2</vaadin.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-jose</artifactId>
            <version>5.6.3</version>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.vaadin</groupId>
                <artifactId>vaadin-bom</artifactId>
                <version>${vaadin.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
            <plugin>
                <groupId>com.heroku.sdk</groupId>
                <artifactId>heroku-maven-plugin</artifactId>
                <version>3.0.3</version>
                <configuration>
                    <appName>axium-centrality</appName>
                    <processTypes>
                        <web>java $JAVA_OPTS -jar target/${project.artifactId}-${project.version}.jar --server.port=$PORT</web>
                    </processTypes>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <profiles>
        <profile>
            <id>production</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>com.vaadin</groupId>
                        <artifactId>vaadin-maven-plugin</artifactId>
                        <version>23.0.5</version>
                        <executions>
                            <execution>
                                <id>frontend</id>
                                <phase>compile</phase>
                                <goals>
                                    <goal>prepare-frontend</goal>
                                    <goal>build-frontend</goal>
                                </goals>
                                <configuration>
                                    <productionMode>true</productionMode>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
</project>

Security configuration :

package fr.xibalba.axiumwebsite.security;

import com.vaadin.flow.server.auth.ViewAccessChecker;
import com.vaadin.flow.spring.VaadinConfigurationProperties;
import com.vaadin.flow.spring.security.RequestUtil;
import com.vaadin.flow.spring.security.VaadinDefaultRequestCache;
import com.vaadin.flow.spring.security.VaadinWebSecurityConfigurerAdapter;
import fr.xibalba.axiumwebsite.website.pages.login.LoginView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import javax.sql.DataSource;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends VaadinWebSecurityConfigurerAdapter {

    public static final String ROLE_QUERY = "SELECT accounts.username, roles.name "  
                                            "    FROM accounts "  
                                            "    LEFT JOIN roles "  
                                            "        ON (SELECT account_id FROM accounts_roles WHERE role_id = roles.id) = accounts.id "  
                                            "    WHERE accounts.username = ?;";

    @Bean
    public PasswordEncoder passwordEncoder() {

        return NoOpPasswordEncoder.getInstance();
    }

    @Autowired
    private DataSource dataSource;


    @Autowired
    private VaadinDefaultRequestCache vaadinDefaultRequestCache;

    @Autowired
    private RequestUtil requestUtil;

    @Autowired
    private ViewAccessChecker viewAccessChecker;

    @Autowired
    private VaadinConfigurationProperties configurationProperties;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth
                .jdbcAuthentication()
                .dataSource(dataSource)
                .usersByUsernameQuery("SELECT username, password, enabled FROM accounts WHERE username = ?")
                .authoritiesByUsernameQuery(ROLE_QUERY)
                .passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        super.configure(http);

        setLoginView(http, LoginView.class);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {

        web.ignoring().antMatchers("/api/**");

        super.configure(web);
    }
}

Security service :

package fr.xibalba.axiumwebsite.security;

import com.vaadin.flow.component.UI;
import com.vaadin.flow.server.VaadinServletRequest;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Component;

@Component
public class SecurityService {

    private static final String LOGOUT_SUCCESS_URL = "/";

    public UserDetails getAuthenticatedUser() {

        SecurityContext context = SecurityContextHolder.getContext();
        Object principal = context.getAuthentication().getPrincipal();
        if (principal instanceof UserDetails) {
            return (UserDetails) context.getAuthentication().getPrincipal();
        }

        return null;
    }

    public void logout() {

        UI.getCurrent().getPage().setLocation(LOGOUT_SUCCESS_URL);
        SecurityContextLogoutHandler logoutHandler = new SecurityContextLogoutHandler();
        logoutHandler.logout(
                VaadinServletRequest.getCurrent().getHttpServletRequest(), null,
                null);
    }
}

Logs : https://pastebin.com/kJ28qZWR

CodePudding user response:

Did you read the logs?

2022-08-03T17:11:42.857267 00:00 app[web.1]: name: null
2022-08-03T17:11:42.938858 00:00 app[web.1]: role not found
2022-08-03T17:11:43.003201 00:00 heroku[router]: at=info method=GET path="/api/roles/?id=0" host=axium-centrality.herokuapp.com request_id=8fcfca84-a102-4252-b4d3-f53f41574710 fwd="109.30.116.102" dyno=web.1 connect=0ms service=270m

You have no user with id=0 in your database.

CodePudding user response:

I found the problem, I configured jpa from application.properties, and appeared to be edit by the server, I put it in a configuration class and it works

  • Related