0

I am using Spring Boot 3.0. I think that I have a configuration error wrt my package structure + annotations, but can't quite figure it out. There are similar questions on here, but I've tried so many variations of the solutions and still scratching my head. Thanks in advance for the help!

The error I am seeing:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'groupController' defined in URL [jar:file:/workspace/modernmail-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/modernmail/web/GroupController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'groupRepository' defined in com.modernmail.model.GroupRepository defined in @EnableJpaRepositories declared on ModernMailApplication: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class com.modernmail.model.Group

My application:

package com.modernmail;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@ComponentScan(basePackages = {"com.modernmail", "com.modernmail.model"})
@EntityScan(basePackages = {"com.modernmail", "com.modernmail.model"})
@EnableJpaRepositories("com.modernmail.model")
@SpringBootApplication
public class ModernMailApplication {

    public static void main(String[] args) {
        SpringApplication.run(ModernMailApplication.class, args);
    }

}

My initializer Component:

package com.modernmail;

import com.modernmail.model.Event;
import com.modernmail.model.Group;
import com.modernmail.model.GroupRepository;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.util.Collections;
import java.util.stream.Stream;

@Component
class Initializer implements CommandLineRunner {

    private final GroupRepository repository;

    public Initializer(GroupRepository repository) {
        this.repository = repository;
    }
    ...

My repository:

package com.modernmail.model;

import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface GroupRepository extends JpaRepository<Group, Long> {
    Group findByName(String name);
}

My entity:

package com.modernmail.model;

import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

import jakarta.persistence.*;
import java.util.Set;

@Data
@NoArgsConstructor
@RequiredArgsConstructor
@Entity
@Table(name = "user_group")
public class Group {

    @Id
    @GeneratedValue
    private Long id;
    @NonNull
    private String name;
    private String address;
    private String city;
    private String stateOrProvince;
    private String country;
    private String postalCode;
    @ManyToOne(cascade=CascadeType.PERSIST)
    private User user;

    @OneToMany(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
    private Set<Event> events;
}

My controller:

package com.modernmail.web;

import com.modernmail.model.Group;
import com.modernmail.model.GroupRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.Optional;

@RestController
@RequestMapping("/api")
class GroupController {

    private final Logger log = LoggerFactory.getLogger(GroupController.class);
    private GroupRepository groupRepository;

    public GroupController(GroupRepository groupRepository) {
        this.groupRepository = groupRepository;
    }

    @GetMapping("/groups")
    Collection<Group> groups() {
        return groupRepository.findAll();
    }

    @GetMapping("/group/{id}")
    ResponseEntity<?> getGroup(@PathVariable Long id) {
        Optional<Group> group = groupRepository.findById(id);
        return group.map(response -> ResponseEntity.ok().body(response))
                .orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
    }

    @PostMapping("/group")
    ResponseEntity<Group> createGroup(@Valid @RequestBody Group group) throws URISyntaxException {
        log.info("Request to create group: {}", group);
        Group result = groupRepository.save(group);
        return ResponseEntity.created(new URI("/api/group/" + result.getId()))
                .body(result);
    }

    @PutMapping("/group/{id}")
    ResponseEntity<Group> updateGroup(@Valid @RequestBody Group group) {
        log.info("Request to update group: {}", group);
        Group result = groupRepository.save(group);
        return ResponseEntity.ok().body(result);
    }

    @DeleteMapping("/group/{id}")
    public ResponseEntity<?> deleteGroup(@PathVariable Long id) {
        log.info("Request to delete group: {}", id);
        groupRepository.deleteById(id);
        return ResponseEntity.ok().build();
    }
}

My pom.xml (commented out items are things I've tried that also didn't work):

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>jakarta.persistence</groupId>
            <artifactId>jakarta.persistence-api</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
        </dependency>
<!--        <dependency>-->
<!--            <groupId>org.hibernate</groupId>-->
<!--            <artifactId>hibernate-core</artifactId>-->
<!--        </dependency>-->
<!--        <dependency>-->
<!--            <groupId>org.hibernate.javax.persistence</groupId>-->
<!--            <artifactId>hibernate-jpa-2.1-api</artifactId>-->
<!--            <version>1.0.0.Final</version>-->
<!--        </dependency>-->
<!--        <dependency>-->
<!--            <groupId>javax.xml.bind</groupId>-->
<!--            <artifactId>jaxb-api</artifactId>-->
<!--            <version>2.3.0</version>-->
<!--        </dependency>-->
Angelica
  • 3
  • 2
  • Can you share controller and Service, if you have it? And property, please. – Игорь Ходыко Jan 14 '23 at 06:32
  • Added the controller & properties to the original post. I don't have a Service I don't think. Thanks! – Angelica Jan 14 '23 at 06:46
  • Can you share full version of pom, please. If you have spring lower than 4.3 you need @Autowired. – Игорь Ходыко Jan 14 '23 at 08:16
  • Oh, I see spring boot 3.0 – Игорь Ходыко Jan 14 '23 at 08:32
  • I have an idea, may be Group is bad name for class and DB rejects it (this word is reserved for Group by may be). Try to change it. – Игорь Ходыко Jan 14 '23 at 08:46
  • I don't get why you need all these annotations in `ModernMailApplication`. Annotation `SpringBootApplication` already contains what you need, i suppose everything will work correct if you remove redundant annotations – timofeevle Jan 14 '23 at 12:21
  • Hi thank you for your suggestions! - I tried removing the annotations and just leaving @SpringBootApplication and see the same error (they might still be redundant but it didn't fix the problem) - I tried changing the name of the Entity away from Group, but I still get the same error for the new name. - For `javax.persistence.Entity`, I thought spring boot 3.0 requires `jakarta.persistence.*` now (https://spring.io/blog/2022/05/24/preparing-for-spring-boot-3-0) am I misunderstanding? – Angelica Jan 14 '23 at 15:03
  • jakarta is from java 8 and highter – Игорь Ходыко Jan 14 '23 at 19:32
  • I've made small copy of your project and it works. I delete jakarta.persistence-api, hibernate-core, hibernate-entitymanager why do we need them? Code doesn't contain hibernate imports, jakarta, it seems, included into boot by default. – Игорь Ходыко Jan 14 '23 at 21:13
  • One more thing, why do you use @RequiredArgsConstructor in entity? Do you Autowire something there? May be I don't know something about new features, but in my opinion AllArgsConsructor NoArgsConstructor are enough. – Игорь Ходыко Jan 14 '23 at 21:19
  • Thank you!! @Игорь Ходыко, deleting some of those annotations worked :) – Angelica Jan 15 '23 at 15:45

3 Answers3

2

You need to remove @RequiredArgsConstructor from entity, AllArgsConsructor NoArgsConstructor are enough.

Delete jakarta.persistence-api, hibernate-core, hibernate-entitymanager. Code doesn't contain hibernate imports, jakarta, it seems, included into boot by default.

0

After migration from SpringBoot 2.x to 3.x I figured out that javax.persistence-api should be replaced with jakarta.persistence-api to solve the issue in my case.

-1

One thing i really don't understand that why are you initizing you bean using construtor? You should autowire your beans and let them manage by spring container. Remove below code from your controller for initializing the repository and use autowire it like beolw.

Remove it -

 private GroupRepository groupRepository;

public GroupController(GroupRepository groupRepository) {
    this.groupRepository = groupRepository;
}

And Add it -

@Autowired private GroupRepository groupRepository;

P.Sanjay
  • 303
  • 1
  • 7
  • Spring autowires via constructors. I prefer constrcutor injection to field injection, as it makes writing unit tests simpler, makes it easier to see what the dependencies of a component are, and allows you to use `@Configuration` classes more easily. – tgdavies Jan 14 '23 at 07:42
  • This answer also doesn't attempt to answer the question. – tgdavies Jan 14 '23 at 07:43
  • Constructer injection is preferred over setter and field injection. Refer: https://stackoverflow.com/questions/21218868/explain-why-constructor-inject-is-better-than-other-options – Dilip Raj Baral Jan 14 '23 at 09:30