Charles
Charles

Reputation: 11758

Spring - How to use @Autowired correctly?

I found a strange behaviour in my Spring App.

The @autowired of an Entity is not working all the time.

I use the Elide project to build an JSONAPI and some custom controllers.

In one controller, one @Autowrited of an entity stays null however it use correctly working when called from Elide.

Controller:

@RestController
public class UploadController {
    @Autowired
    private ProjectRepository projectRepository;

    @PostMapping(value = "/api/projects/{projectId}/upload")
    public String uploadItem(@PathVariable long projectId, @RequestParam("file") MultipartFile file,
                              @RequestParam("projectName") String projectName,
                              RedirectAttributes redirectAttributes) throws IOException {
        Project project = projectRepository.findOneByProjectIdAndName(projectId, projectName);
        Integer result = project.getNumberOfItems();

        return "";
    }
}

Entity

@Setter
@NoArgsConstructor
@Table(name = "projects")
@Entity
@Include(rootLevel = true, type = "projects")
public class Project extends DiffShelfBase {

    @Autowired
    @Transient
    private ItemRepository itemRepository;

    @Transient
    @ComputedAttribute
    public Integer getNumberOfItems() {
        return itemRepository.countByProjectId(this.getId());
    }
}

Repository

@Repository
@Transactional
public interface ItemRepository extends JpaRepository<Item, Long> {
    Integer countByProjectId(long projectId);
}

Configuration

@Configuration
@EnableSpringConfigured
public class MyConfiguration {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedMethods("*")
                        .allowedOrigins("http://localhost:4200");
            }
        };
    }
}

I don't understand why but the itemRepository in null in Project.getNumberOfItems.

Upvotes: 1

Views: 513

Answers (3)

Sharan Arumugam
Sharan Arumugam

Reputation: 363

An Entity should be a glorified POJO, never complicate it embedding repos inside

so autowire ItemRepository a level up, atUploadController itself.

@RestController
public class UploadController {

    @Autowired
    private ProjectRepository projectRepo;

    @Autowired
    private ItemRepository itemRepo;

    @PostMapping(value = "/api/projects/{projectId}/upload")
    public String uploadItem(@PathVariable long projectId, @RequestParam("file") MultipartFile file,
                              @RequestParam("projectName") String projectName,
                              RedirectAttributes redirectAttributes) throws IOException {

        Project project = projectRepo.findOneByProjectIdAndName(projectId, projectName);
        Integer result = itemRepo.countByProjectId(project.getId());

        return "";
    }
}

and as a good practice, you can always do a constructor injection making it easy to test

e.g. instead of

@Autowired
private ProjectRepository projectRepo;

@Autowired
private ItemRepository itemRepo;

do a constructor injection

private final ProjectRepository projectRepo;
private final ItemRepository itemRepo;

@Autowired
public UploadController(final ProjectRepository projectRepo, final ItemRepository itemRepo) {
    this.projectRepo = projectRepo;
    this.itemRepo = itemRepo;
}

this way,

  1. it is easy to test by passing mockito instances.
  2. you can make them final (which is not possible with @Autowire on variable directly)

Upvotes: 0

Christian
Christian

Reputation: 22343

The problem you have is, that your Project is no managed by spring. You have to add the @Configurable annotation to your class. Then your Autowired annotation will work.

But I would really refactor your code. You should not have spring-objects in your Entities.

Upvotes: 1

Vlad Hanzha
Vlad Hanzha

Reputation: 464

This is not a way how you should do that. Don't use @Autowired in your entities. This annotation is managed by Spring, but your entities are managed and created by Hibernate and it doesn't care about Spring annotations. You could find another way to add this property to your entity(let it be field in a database for example).

Upvotes: 3

Related Questions