I wrote this code
#Controller
public class StudentsController {
private ArrayList<student> students = new ArrayList<>();
private IStudentsRepository studentsRepository;
#GetMapping("/")
public String index(Model model){
model.addAttribute("students", students);
return "index";
}
#GetMapping("/create")
public String create(#ModelAttribute student student) {
studentsRepository.create(student);
return "create";
}
.....
}
for a web application and I get this error java.lang.NullPointerException: null
at com.example.demo.Controller.StudentsController.create(StudentsController.java:27) ~[classes/:na]
When I try to access the page create with its functionalities it doesn't work just gives me that error what is the problem? Also when I initialize the IStudent Repository interface IntelliJ tells me that studentsRepository is not assigned even if I used it to create method.
You are not injecting IStudentsRepository. Use #Autowired
You can use Field Injection like this
#Autowired
private IStudentsRepository studentsRepository;
Or the best way would be to use Constructor Injection.
#Controller
public class StudentsController {
private ArrayList<student> students = new ArrayList<>();
private final IStudentsRepository studentsRepository;
#Autowired
public StudentsController(final IStudentsRepository studentsRepository) {
this.studentsRepository = studentsRepository;
}
Related
I am currently working on a project where I have created the following custom Repository:
public interface ServiceRepository<T extends ServiceEntity> extends JpaRepository<T, UUID>, ServiceRepositoryCustom {
}
public interface ServiceRepositoryCustom {
List<ServiceEntity> findAllContainingName(String query);
}
#Repository("Repo")
public class ServiceRepositoryCustomImpl implements ServiceRepositoryCustom {
private final EntityManager em;
public ServiceRepositoryCustomImpl(EntityManager em) {
System.out.println("I got constructed");
this.em = em;
}
#Override
public List<ServiceEntity> findAllContainingName(String name) {
System.out.println("I got called with: " + name);
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<ServiceEntity> cq = cb.createQuery(ServiceEntity.class);
Root<ServiceEntity> serviceEntity = cq.from(ServiceEntity.class);
List<Predicate> predicates = new ArrayList<>();
if(name != null) {
// predicates.add(cb.equal(serviceEntity.get("name"), name));
predicates.add(cb.like(serviceEntity.get("name"), name + "%"));
}
cq.where(predicates.toArray(predicates.toArray(new Predicate[0])));
return em.createQuery(cq).getResultList();
}
}
The print statement "I got called with: " never gets called. So for whatever reason Spring Boot is not running the method through my custom implementation.
Any suggestions? Any help is much appreciated
Edit:
Here is the code that injects and uses the Repository in question
#Repository
public interface PineappleServiceRepository extends ServiceRepository<PineappleServiceEntity> {
}
#Component("Registry")
#DependsOn({"Context", "Repo"})
public class Registry {
private final List<ServiceRepository<? extends ServiceEntity>> serviceRepositories = new ArrayList<>();
public Registry(PineappleServiceRepository pineappleServiceRepository) {
this.serviceRepositories.add(pineappleServiceRepository);
}
}
Edit 2:
The code prints "I got constructed"
Edit 3:
Class where findAllContainingName is called
#RestController
#RequestMapping("/test")
#DependsOn("Registry")
public class ServiceController {
private final Registry registry;
public ServiceController(#NotNull Registry registry) {
this.registry = registry;
}
#GetMapping("")
List<ServiceEntity> all(#RequestParam("q") String query) {
return getAllServices(query);
}
private #NotNull List<ServiceEntity> getAllServices(String query) {
List<ServiceEntity> response = new ArrayList<>();
for(ServiceRepository<? extends ServiceEntity> repo: this.registry.getServiceRepositories()){
response.addAll(repo.findAllContainingName(query));
}
return response;
}
}
Edit 4:
Here the entities:
#Entity
#Table(name = "services")
public abstract class ServiceEntity {
protected #Id
UUID id = UUID.randomUUID();
protected String name;
// Constructor + Getters and Setters
}
#Entity
public class PineappleServiceEntity extends ServiceEntity {
// Additional Properties, matching Constructors, Getters and Setters
}
So I was able to reproduce your problem and fix it. Issue with your code is that your PineappleServiceRepository is not extending ServiceRepositoryCustom directly. It seems your repository needs to implement it directly if you are accessing custom repository methods from that repository. I got that idea from this post.
So to fix your issue, either remove PineappleServiceRepository(as you don't have any properties in PineappleEntity) and use ServiceRepository to call that custom method or make PineappleServiceRepository extend ServiceRepositoryCustom.
I have pushed changes to GitHub with fix. You can take a look. If you want to keep PineappleServiceRepository and access custom method using this repository, let me know, I can update code.
I am writing a springboot application that should calculate the grade of a student. You should read the name of the student from command line, and call an API that will return the student ID in JSON. Then I will take the Student ID and call another API that would return the total of the student Marks in JSON. Then I should calculate the grade accordingly. The calculation is as follow: F=<60, D=<65, C=< 75, B=<85, A=<100.
Below is my hypothetical view of how I will write the project, I think I know how to write the code that will function, but I am stuck with what is the best skeleton for the project or design of classes. Below is how I think it should be written.
#Controller
// Rest call to the Student API
public class StudentController {
private static final Logger log = LoggerFactory.getLogger(ClientController.class);
private RestOperations rest;
private Config config; //to read the URL
.....
#Controller
// Rest call to the grades API
public class GradsController
{
private static final Logger log = LoggerFactory.getLogger(ClientController.class);
private RestOperations rest;
private Config config; //to read the URL
.....
Configuration
#ConfigurationProperties(prefix="api.call")
public class Config {
private String URL;
.....
public class Student {
#JsonProperty("Data")
private Elements[] elements;
.......
public class Grads {
#JsonProperty("Subjects")
private String[] subjects;
.......
#Service
public class CalculateGrade {
private String marks;
private HashMap <String, Integer> gradeMap;
CalculateGrade( String marks)
{
this.marks = marks;
this.carName = carName;
fillMap();
}
private void fillMap()
{
gradeMap= new HashMap<>();
gradeMap.put("A",100);
gradeMap.put("B", 85 );
..........
}
public String getGrade()
{
// do calculations;
}
#SpringBootApplication
#ConfigurationPropertiesScan ("Config")
public class MyApplication {
private static final Logger log = LoggerFactory.getLogger(MyApplication.class);
#Autowired StudentController StudentController;
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
For a skeleton, it looks quite sensible. Controllers to translate from Web to Domain and the business logic in domain/application services (CalculateGrade). Looks a lot like the Hexagonal architecture ("Ports&Adapters").
I have a java class that I am setting up to store LoL champions in a project also using lombok (thus the lack of getters and setters) and Spring. The class looks like this:
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Champion {
#Id
private String champName;
private String role;
private List<String> type; // <--- how do I populate this?
private String phrase;
private List<Champion> counterTo; //<--- or this?
private List<Champion> counteredBy;// <-- you get the idea.
}
I'm overriding the run() method from spring using commandLineRunner in my main application class but I don't know how to populate the lists when I invoke the constructor using Spring's .save() method when persisting into my MongoDB. Can anyone help?
Here is the main class below for context:
public class PlaygroundApplication implements CommandLineRunner {
#Autowired ChampionRepository repo;
public static void main(String[] args) {
SpringApplication.run(PlaygroundApplication.class, args);
}
#Override
public void run(String...args){
repo.deleteAll();
//repo.save("CHAMPION_ENTITY_GOES_HERE);
}
}
If I understand you correctly, you can try new a object and set the param it or Custom constructor
I'm planning to create my objects in my Spring MVC using the below setup but How can I inject values to my MyService ie; instantiate the object with default value...
public class MyController {
private MyService myService;
#Autowired
public void setMyService(MyService aService) { // autowired by Spring
this.myService = aService;
}
#RequestMapping("/blah")
public String someAction()
{
// do something here
myService.foo();
return "someView";
}
}
MyService
class Myservice(){
String servicename;
public Myservice(servicename){
this.servicename = servicename;
}
}
Without Spring
MyService first = new MyService("firstservice");
MyService second = new MyService("secondservice");
Just declare your constructor with #Autowired to mark it as the constructor to use and its parameter with #Value to indicate the value to use.
#Autowired
public Myservice(#Value("example") String servicename){
Or use a placeholder
#Autowired
public Myservice(#Value("${placeholder.key}") String servicename){
Firstly, your exam are wrong on using Spring DI. To inject Myservice type to another You should declare MyService as a interface instead:
interface Myservice(){
public void foo();
}
After that, declare an implementation of this interface (again, use Spring DI to inject String type):
class BarService() implements Myservice{
String servicename;
#Autowired
public Myservice(#Value("servicename") String servicename){
this.servicename = servicename;
}
public void foo(){
}
}
Converting my web-application to Spring. Autowiring is successful in cases where it is initiated in Spring context but fails in other situations, as it should.
I have a MangaBean which has a property named genre. Genre's value should be one from the excepted set of genres. I have placed the validations in the bean itself. Something like this:
#Component
public class MangaBean{
private String title;
private String author;
private String isbn;
private String genre;
//getters
public void setTitle(String title){
//validations
}
public void setGenre(String genre){
boolean result=MangaUtil.verifyGenre(genre);
if(result){
this.genre=genre;
}else{
this.genre=null;
}
}
}
The util calls the method that fetches set of genres from the table and validates the provided genre.
#Component
public class MangaUtil{
#Autowired
MangaDao mDao;
public static boolean verifyGenre(String genre){
List<String> genres=mDao.getGenresList(); //null pointer exception
//do validations
}
}
MangaDao contains an autowired NamedParameterJDBCTemplate which fetches genres from DB.
Code for MangaDao:
#Repository
public class MangaDao{
#Autowired
private NamedParameterJdbcTemplate template;
public List<String> getGenresList(){
String query="select genres from manga_table";
Map<String,String> paramMap=new HashMap<String, String>();
return template.queryForList(query, paramMap, String.class);
}
}
In the above arrangement, the call to MangaUtil works fine when I autowire MangaUtil as well. Example:
#Component
public class MangaBean{
#Autowired
MangaUtil mangaUtil;
private String title;
private String author;
private String isbn;
private String genre;
//getters
public void setTitle(String title){
//validations
}
public void setGenre(String genre){
boolean result=mangaUtil.verifyGenre(genre);
if(result){
this.genre=genre;
}else{
this.genre=null;
}
}
}
But if I use autowiring inside a bean, the autowire would fail in cases I instantiate the bean myself like MangaBean mb=new MangaBean(). Please advice for a situation like this. I want to call the validator method from my bean without any autowiring in bean itself. Is it possible?. If not, is there any way I can store a list of genres and use it in the bean to validate my data. Please advice.
By default autowiring works only for Spring managed beans i.e. that are created by Spring. To make it work for beans instantiated with e.g. new see the Spring docs:
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-atconfigurable
You need to use #Configurable annotation and configure AspectJ as per the documentation.
Maybe not a real answer to your problem. But I wonder how you were able to compile this code:
#Component
public class MangaUtil(){ // <<< parentheses not allowed here
#Autowired
MangaDao mDao;
public static boolean verifyGenre(String genre){
List<String> genres=mDao.getGenresList(); // <<< you are referencing a non static attribute from a static method
}
}