Spring Boot #Autowired does not work with class of different package - java

The structure of my project like the following:
I am sure everything okay but only one thing make the problem is #Autowired in StoredProcedureSpringDataJpaApplication.java like the following:
public class StoredProcedureSpringDataJpaApplication implements CommandLineRunner {
#Autowired
private StudentRepository stu;
public static void main(String[] args) {
SpringApplication.run(StoredProcedureSpringDataJpaApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
// TODO Auto-generated method stub
List<Student> students = stu.findAll();
students.forEach(System.out :: println);
}
}
Error description is:
Field stu in com.example.demo.StoredProcedureSpringDataJpaApplication required a bean of type 'com.repository.StudentRepository' that could not be found.
I know this is familiar question ,I did so many way to try to solve this problem in the internet even in stackoverflow but all can not solve my problem.
Help me solve this problem.

Use #ComponentScan({"com.example.demo", "com.repository"})
By default without this annotation it considers only annotations that exist inside the package where your #SpringBootApplication is declared, aka com.example.demo
Also together with the #ComponentScan use the following
#EnableJpaRepositories(basePackages = {"com.repository"})

Your package structure is incorrect StoredProcedureSpringDataJpaApplication.java should be in the root package. Another way is component scan placing annotation over StoredProcedureSpringDataJpaApplication.java. In your case, it should be like
This won't work for the repository class and as you have a different package structure so #EnableJpaRepositories(basePackages = "com.repository") will help you resolve this issue.

This happens because #SpringBootApplication does only scan in the package where it is defined.
Make sure it is placed at the root of your project and everything that should be scanned below it. For example:
com
- example
- demo
- StoredProcedureSpringDataJpaApplication.java
- repository
- StudentRepository.java

Related

SpringBoot #Autowire why does this example work?

I have created this class:
import org.springframework.stereotype.Component;
...
#Component("notTheNameTestMe") //shouldnt this only work with testMe ?
public class TestMe {
public void showMsg() {
System.out.println("Autowiring works");
}
}
And I'm using it this way in a second class (or better: controller):
import com.example.TestMe; //shouldnt this be not necessary with autowire? But getting error else...
...
#Autowired
private TestMe testMe;
...
this.testMe.showMsg();
But this works perfectly (so maybe Im not really using autowire here?), it even works if I rename the whole TestMe class to TestMeSomething (if I adjust the import in the second class)
I dont really understand what #Autowired does. I thought it just scans for SpringBoot Components (which are named by the string in #Component() and when it finds a match it Injects the dependancy. But in my example the match is impossible and I still can see the message "Autowiring works" in the console. This shouldnt be like this if I would really use autowire here or? What am I understanding in a wrong way? What is the difference to using new TestMe() then? I have the dependancy already with the import or? So not a real dependancy injection, or?
Spring is not operating on the name in the #Component annotation. Rather it's using the name of the class. It's simply finding a class named TestMe because that's the type of the variable you've annotated with #Autowired.

Usage of non public classes in spring java-based config

It seems to be a simple question but yet i couldn't find clear answer while searching documentation and forums. I'm migrating from xml to java-based config (Spring 5.1.9). Due to some legacy restrictions in xml config i need to create a bean from some side library's non public class:
SampleClass.class
package side.library
class SampleClass {
//... some code here
}
context.xml
...
<bean id = "sampleId" class "side.library.SampleClass">
...
And this works fine since Spring uses reflection inside and it creates bean without any problems at compile/runtime, but in java-based config usage of such class leads to an access error:
package my.configuration;
import side.library.SampleClass; // 'side.library.SampleClass' is not public in 'side.library'. Cannot be accessed from outside package
#Configuration
public class JavaConfiguration{
#Bean
public SampleClass sampleClass() {
return new SampleClass(); // same error text
}
}
So, what is the proper way to deal with this sutiation? Using reflection libs in #Configuration class to reach this class seems to be a bad idea.
just a workaround: create a wrapper class in the outer project in the same package and use this class in your configuration.
package com.legacy;
public class Wrapper {
private LegacyImpl legacyImpl;
public Wrapper()
this.legacyImpl = new LegacyImpl();
}
public void wrappedMethod() {
this.legacyImpl.wrappedMethod();
}
}

Springboot #EntityScan not working

I have a Springboot application and my entity model is separated from my main application included as dependency.
my Application.java is located in this package com.a.b.c
#SpringBootApplication
#EntityScan("com.a.b")
public class Applciation
{
public static void main(String args[])
{
SpringApplication.run(Applciation.class, args);
}
}
and my entity model is located in another project inside this package com.a.b
But I'm getting an error: Caused by: java.lang.IllegalArgumentException: Not a managed type: class
I can relate to you. I have spent countless hours regarding this.
I'll divide your question to 3 parts (I will use "entity-project" and "spring-project" to refer to the project containing entity classes and main project trying to incorporate entity classes) :
Part 1 of 3: Making sure your entity classes are exposed in entity-project.
Create a Config at the root of entity-project
package com.a.b
#Configuration
#Import ({Entity1.class, Entity1Repo.class, Entity1Key.class,
Entity2.class, ... })
class EntityConfig {}
Part 2 of 3: Making sure your entity classes are in the classpath of spring-project.
Since you are using SpringBoot, I'm sure you are using maven (or Gradle).
Anyway, make sure you maven install the entity-project with entity classes:
cd /path/to/entity-project/
mvn install -DskipTests
In spring-project's maven file, include to the entity-project.
Part 3 of 3: Use the EntityScan annotation.
It is just my taste, but I prefer using basePackageClasses instead of basePackage.
#SpringBootApplication
#EntityScan(basePackageClasses = {Entity1.class})
// use basePackageClasses to avoid type errors
#Import({com.a.b.EntityConfig.class}) // this is what you are missing
public class Applciation
{
public static void main(String args[])
{
SpringApplication.run(Applciation.class, args);
}
}
Viola!

Spring #Value to wire a Resource instance pointing to a JSON file

I've seen very few examples that uses this and was trying to get it to work but unable to:
package com.acme.service;
public class SampleServiceTest {
#Value("classpath:data.json")
private Resource jsonData;
#Test
public void testThis() {
String json = String.join("\n", Files.readLines(jsonData.getFile(), Charset.defaultCharset()));
}
}
Where my file structure (follows Maven standard) is as follows:
data-microservice (top folder)
-src/test/java/com/acme/service/SampleServiceTest
-src/test/resources/data.json
I've tried several of these but doesn't seem to work:
classpath:data.json
classpath:/data.json
classpath:src/test/resources/data.json
classpath:/src/test/resources/data.json
Looking to get help on this please, and if you could also provide a background on correct path (i.e. why that correct path works).
Found it, I was being silly and running test without any Spring context. It was a matter of just putting in these annotations on the test class:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
public SampleServiceTest {
//body here
}
And the "classpath:data.json" works!
Although if someone can explain why the classpath works without specifying the directories (src/test/resources) works, that would really be helpful.

Play Framework Dependency Injection

I've been looking all over Google to find some useful information on how to use Guice/Spring DI in Play Framework 2.1
What I want to do is to Inject several Services in some DAO's and vice versa.
Just need some clarification on this - With play 2.1, do you have to use an # annotation within the routes file for DI?
I've looked at this guide here - https://github.com/playframework/Play20/blob/master/documentation/manual/javaGuide/main/inject/JavaInjection.md
and applied the following steps creating a Global class in app and adding the GUICE dependencies in Build.scala but keep on getting a null pointer exception when invoking on the injected object.
Has anyone been able to get DI working in Play 2.1 using Guice? I've seen examples across the internet but they all seem to be using DI within the controller.
I noticed you are using Java. Here is how I got it to work for injecting into a controller.
First, I created the following 4 classes :
MyController:
package controllers;
import play.mvc.*;
import javax.inject.Inject;
public class MyController extends Controller {
#Inject
private MyInterface myInterface;
public Result someActionMethodThatUsesMyInterface(){
return ok(myInterface.foo());
}
}
MyInterface:
package models;
public interface MyInterface {
String foo();
}
MyImplementation2Inject:
package models;
public class MyImplementation2Inject implements MyInterface {
public String foo() {
return "Hi mom!";
}
}
MyComponentModule:
package modules;
import com.google.inject.AbstractModule;
import models.MyInterface;
import models.MyImplementation2Inject;
public class ComponentModule extends AbstractModule {
#Override
protected void configure() {
bind(MyInterface.class).
to(MyImplementation2Inject.class);
}
}
Now the final part, that took me a silly long time to figure out, was to register the module. You do this by adding the following line to the end of the application.conf file, which is located in the conf directory:
play.modules.enabled += "modules.MyComponentModule"
I hope this was helpful to you. :)
I use cake pattern and my own version of Global overriding getControllerInstance
https://github.com/benjaminparker/play-inject
Cheers
Ben
Sorry, this is a late response, but here's our example
https://github.com/typesafehub/play-guice
Have you tried using some different approach to DI than Guice?
We also tried implementing a project with Guice or Spring but ended in registering our dependencies in objects that implement trait such as:
trait Registry {
def userDao: UserDao
...
}
object Registry {
var current: Registry = _
}
object Environnment {
object Dev extends Registry {
val userDao = ...
//implement your environment for develpment here
}
object Test extends Registry {
val userDao = ...
//implement your ennviroment for tests here e.g. with mock objects
}
}
Another good approach wich might fit for you is the cake pattern (just google for it).

Categories

Resources