Spring boot JPA with different parent for entity and service - java

I have two different maven projects in first I am trying to keep two modules one for "repository and entities" and second for the services. The second project is containing only one module with the "controllers". Now I am having many problems first is "Not a managed type" for the entities. Another thing if I keep everything in one module or even in different modules with one parent project, it works flawlessly, however, I am just trying to put the different package in different project and module
The entityscan, enablejparepositries and all others are working, the debug states:
name: default
persistence provider classname: null
classloader: sun.misc.Launcher$AppClassLoader#42a57993
excludeUnlistedClasses: true
JTA datasource: null
Non JTA datasource: HikariDataSource (null)
Transaction type: RESOURCE_LOCAL
PU root URL: file:/F:/Software/MavenRepo/com/company/repo/1.0.0/repo-1.0.0.jar
Shared Cache Mode: UNSPECIFIED
Validation Mode: AUTO
Jar files URLs []
Managed classes names [
com.company.sitemap.repo.Page]
Mapping files names []
Properties []
However, At the last it states
Caused by: java.lang.IllegalArgumentException: Not a managed type: class com.company.sitemap.repo.Page
and shows error starting the application.
Can you please help me out with this?
Here is my Application class file
package com.company.sitemap;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import com.company.sitemap.repo.SitemapRepoConfig;
import com.company.sitemap.service.SitemapConfig;
#SpringBootApplication
#EnableJpaRepositories(basePackageClasses = { SitemapRepoConfig.class })
#EntityScan(basePackages = {"com.nie.learn.sitemap.repo"})
#ComponentScan(basePackageClasses = { SitemapConfig.class, SitemapRepoConfig.class })
public class Sitemap extends SpringBootServletInitializer {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(Sitemap.class, args);
for (String name : applicationContext.getBeanDefinitionNames()) {
System.out.println(name);
}
}
}
The entity class resides in different project and module. Let say Project-libs and module module-repo. I am trying to add this as a maven dependency.
The entity file is as follows:
package com.company.sitemap.repo;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity
public class Page {
Repo config to scan repo classes.
package com.company.sitemap.repo;
import org.springframework.context.annotation.Configuration;
#Configuration
public class SitemapRepoConfig {
}
Service config to scan service classes:
package com.company.sitemap.service;
import javax.validation.constraints.NotNull;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.company.sitemap.repo.PageRepository;
#Configuration
public class SitemapConfig {
#Bean
#NotNull
public SitemapService service(#NotNull PageRepository repo) {
return new SitemapService(repo);
}
}

I'll show you an example that helps us in a somewhat different case. This kind of config is used for Module1TestConf to allow separate modules testing using Spring boot slicing (#DataJpaTest, etc.) in our multi-module Gradle project to avoid loading all the context.
We just limit our module scanning to the current module + additional entities.
#SpringBootConfiguration
#EnableAutoConfiguration
#EntityScan(
basePackages = "your.other.module.package.entity",
basePackageClasses = {SomeEntity1.class, SomeEntity2.class}
)
#ComponentScan(
value = "your.current.module.package",
excludeFilters = {
#ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter),
#ComponentScan.Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter)})
That is basically what is #SpringBootApplication is doing under the hood.
So I'm not 100% sure that it would help you. Is there a valid reason to have the projects kept as separate maven projects (use Gradle! :) )?
Anyway, you just need to make those entities scanned by Spring and become manageable...
Also try specifying entity classes directly in basePackageClasses.

You need to scan the package so that spring can create beans automatically. You are defining Page as bean but not scanning it. For scan you need to add
#ComponentScan(basePackages = { "com.nie.learn.*" })
If you have already added it than please check if Page is annotated with #Entity like below
#javax.persistence.Entity
public class Page {}

#SpringBootApplication
#EnableJpaRepositories(basePackageClasses = { com.company.sitemap.repo})
#EntityScan(basePackages = {"com.company.sitemap.repo"})
public class Sitemap extends SpringBootServletInitializer {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(Sitemap.class, args);
for (String name : applicationContext.getBeanDefinitionNames()) {
System.out.println(name);
}
}
}
Try the above configuration.

Related

Field repository in '' required a bean named 'entityManagerFactory' that could not be found

So I've been learning Spring for a few weeks. I am trying to make a simple project involving a Controller -> Service -> Repository -> Database pattern.
I started having this problem, but could not find the solution to it. I stumbled upon some similar problems online with the same error, but none of them gave my solution, everything seems normal in my project.
This is the error on output:
***************************
APPLICATION FAILED TO START
***************************
Description:
Field repository in com.Library.services.LibraryService required a bean named 'entityManagerFactory' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean named 'entityManagerFactory' in your configuration.
This are the files of my project (file tree):
This is my code:
Main class:
package com.Library;
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;
import org.springframework.web.bind.annotation.RestController;
#SpringBootApplication
#EntityScan("com.Library.services")
#EnableJpaRepositories("com.Library.repositories")
public class LibraryApplication {
public static void main(String[] args) {
SpringApplication.run(LibraryApplication.class, args);
}
}
Model:
package com.Library.models.dtos;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
#Getter
#Setter
#Entity
public class BookCategory {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long Id;
private String Name;
}
Repository:
package com.Library.repositories;
import com.Library.models.dtos.BookCategory;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public interface BookCategoryRepository extends JpaRepository<BookCategory,Long> {
List<BookCategory> findAll();
}
Service:
package com.Library.services;
import com.Library.models.dtos.BookCategory;
import com.Library.repositories.BookCategoryRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class LibraryService {
#Autowired
BookCategoryRepository repository;
public List<BookCategory> getAllCategories() {
return repository.findAll();
}
}
Controller:
package com.Library.controllers;
import com.Library.models.dtos.BookCategory;
import com.Library.services.LibraryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#CrossOrigin(origins = "*", allowedHeaders = "*")
#RestController
public class LibraryController{
#Autowired
LibraryService libraryService;
public List<BookCategory> getAllCategories() {
return libraryService.getAllCategories();
}
}
What could be the issue?
This bean definition is usually provided automatically by Spring Boot Auto-Configuration. The spring reference manual explains how to diagnose such issues:
The Spring Boot auto-configuration tries its best to “do the right thing”, but sometimes things fail, and it can be hard to tell why.
There is a really useful ConditionEvaluationReport available in any Spring Boot ApplicationContext. You can see it if you enable DEBUG logging output. If you use the spring-boot-actuator (see the Actuator chapter), there is also a conditions endpoint that renders the report in JSON. Use that endpoint to debug the application and see what features have been added (and which have not been added) by Spring Boot at runtime.
Many more questions can be answered by looking at the source code and the Javadoc. When reading the code, remember the following rules of thumb:
Look for classes called *AutoConfiguration and read their sources. Pay special attention to the #Conditional* annotations to find out what features they enable and when. Add --debug to the command line or a System property -Ddebug to get a log on the console of all the auto-configuration decisions that were made in your app. In a running application with actuator enabled, look at the conditions endpoint (/actuator/conditions or the JMX equivalent) for the same information.
In your case, a simple full text search finds that Hibernate is auto-configured by org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, which is declared as follows:
#AutoConfiguration(after = { DataSourceAutoConfiguration.class })
#ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class, EntityManager.class, SessionImplementor.class })
#EnableConfigurationProperties(JpaProperties.class)
#Import(HibernateJpaConfiguration.class)
public class HibernateJpaAutoConfiguration {
}
As you can tell from the ConditionalOnClass annotation, this configuration is only applied if your classpath contains the classes LocalContainerEntityManagerFactoryBean from spring-orm-jpa, EntityManager from the JPA spec, and SessionImplementor from the hibernate jar.
Most likely, you are missing one of these JAR files (maven dependencies), or have the wrong version of one. The ConditionEvaluationReport should tell you which, and the precise package names to check for.

Java Spring bean creation and access from external jar

I have spring jar for my entity beans created as export--java--JARfile, where i have beans defined as follows:
package com.my.beans;
#Component("expBean")
public class ExpBean {
}
I also have config in this jar
package com.my;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class pBeanConfig {
#Bean
public ExpBean getExpBean() {
return new ExpBean();
}
}
I have client spring application where i am adding above jar having only beans as by external dependency and trying to get my beans when spring app starts using following code in main code in client spring app.
package com.my;
import java.util.Arrays;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication()
#ComponentScan("com.my")
public class Application {
public static void main (String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
WMyBean bean = (WMyBean) ctx.getBean("expBean");
bean.doSomething();
}
}
But when checked the list of bean definition printed, i do not see my bean from external jar and also i get following error.
"Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'expBean' available"
I tried many options but not sure whats missing.
Option 1
#ComponentScan("com.my")
#SpringBootApplication
public class Application {
Option 2
#ComponentScan({"com.my"})
#SpringBootApplication
public class Application {
Need valuable inputs on step that i am missing out.
Question 1: Is it mandatory for me to do config change in client project to access my dependent jar entities?
Question 2: Can it be dynamic, load all entities without configuration as #bean in client project config?
Question 3: Do i need to build client jar every-time i change my dependent jar file with more entities?
Thanks
First I am assuming the build tool is Gradle, but you can import the jar as a local file like this for the sake of experiment:
dependencies {
implementation files('libs/something_local.jar')}
Then, assuming you use Eclipse you can right click the project folder and do a 'Gradle refresh'
In your config class you can either autowire in the bean for the class as a whole , or choose to create it whenever an instance of the class is created by declaring it within the class constructor:
import org.springframework.beans.factory.annotation.Autowired;
//I also have config in this jar
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class pBeanConfig {
//Autowire in the bean for the whole class.
#Autowired
ExpBean expBean;
public pBeanConfig() {
//Or, you may want to have a bean instance whenever the pBeanConfig class is instantiated.
ExBean exBean;
}
}
I'm making a number of assumptions for this answer like it's a Gradle project, but you can set up a similar dependency for Maven by modifying the POM file to include that file.
Build tools aside, in Eclipse you can simply add the jar file by right clicking the project and build path => configure build path => add external jar file.
UPDATE:
This pic describes how I set up the bean within a separate jar file via eclipse. The steps should show that the bean can be reached with this project even though it's in a jar and not in the project itself.

How to autowire a component in a dependency/external jar in Spring? [duplicate]

This question already has answers here:
How can I #Autowire a spring bean that was created from an external jar?
(5 answers)
Closed 3 years ago.
I have a Spring Boot project and I can't get components from an external jar to be autowired. When I try to, I got a org.springframework.beans.factory.NoSuchBeanDefinitionException saying that can't find a bean with that name available.
I tried some solutions found in similar questions, like these ones:
How to autowire #service from external Jar in Spring
Spring Boot #autowired does not work, classes in different package
How can I #Autowire a spring bean that was created from an external jar?
..but still can't managed it to work.
Here is an example of what I'm trying to accomplish:
Here is boot class in the Spring Boot project spring-project-example
package com.springdi.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import com.dependency.example.DependencyBasePackageClass;
import com.dependency.example.somepackage.SomeBean;
#SpringBootApplication
#ComponentScan(basePackages = {"com.springdi.example"}, basePackageClasses = DependencyBasePackageClass.class)
public class SpringProjectExampleApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringProjectExampleApplication.class, args);
String beanName = SomeBean.class.getName();
System.out.printf("%s can be autowired: %s\n", beanName, String.valueOf(context.containsBean(beanName)).toUpperCase());
}
}
It's just a simple Spring Boot project checking if it is possible to autowire a component present in the dependency jar.
Here is the component in the jar (dependency-example-1.0.0.jar)
package com.dependency.example.somepackage;
import org.springframework.stereotype.Component;
#Component
public class SomeBean {
public void someMethod() {
System.out.println("Some process...");
}
}
And here is the base package class of this same jar
package com.dependency.example;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* Just a class to serve as the root for component
* scanning in "com.dependency.example" and its sub-packages
*/
#Configuration
#ComponentScan
public class DependencyBasePackageClass {
}
I've already tried #Import(DependencyBasePackageClass.class) in SpringProjectExampleApplication and #ComponentScan with basePackages and basePackageClasses, but no success.
I also tried using #SpringBootApplication(scanBasePackageClasses = {SpringProjectExampleApplication.class, DependencyBasePackageClass.class})
and the not type safe #SpringBootApplication(scanBasePackages = {"com.springdi.example", "com.dependency.example"}).
#Configuration #ComponentScan({"com.dependency.example"}) also fails, context.containsBean("com.dependency.example.somepackage.SomeBean") still returns false.
This jar is included in classpath and in the pom.xml as a dependency
<dependencies>
<!-- other dependencies -->
<dependency>
<groupId>com.rbaggio</groupId>
<artifactId>dependency-example</artifactId>
<version>1.0.0</version>
<scope>system</scope>
<systemPath>${basedir}/lib/dependency-example-1.0.0.jar</systemPath>
</dependency>
</dependencies>
Could it be the location of the jar, the way it is included or some extra configuration needed?
I'd appreciate any help! Thanks in advance.
Okey some basic things, you have mixed up your packages a bit.
#SpringBootApplication will scan all classes in packages below the class this is annotated on. This annotation is an alias for #EnableAutoConfiguration, #Configuration and #ComponentScan means that #ComponentScan(basePackages = {"com.springdi.example"}, basePackageClasses = DependencyBasePackageClass.class) is not needed.
com.springdi.example // class with #SpringBootApplication annotation
|
|
|
com.springdi.example.* // Will find all #Service, #Component, #Configuration
// in subpackages below the #SpringBootApplication
// annotation
You can read more about the annotation here SpringBootApplication
Since your other annotated classes are NOT in the same package structure as the #SpringBootApplication you need to define all the places you want to scan for annotations.
#SpringBootApplication(scanBasePackages = {"com.springdi.example", "com.dependency.example"})
will probably include all the packages that you want to scan through.

SpringBoot error : No bean named 'myController' available

I am building a basic program of "hello world" in SpringBoot
Code
MyController.java
package controllers;
import org.springframework.stereotype.Controller;
#Controller
public class MyController {
public String hello() {
System.out.println("Hello World");
return "foo";
}
}
DemoApplication.java
package di.prac;
import java.util.Arrays;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import controllers.MyController;
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext ctx=SpringApplication.run(DemoApplication.class, args);
MyController m = (MyController)ctx.getBean("myController");
m.hello();
System.out.println("*******"+Arrays.asList(ctx.getBeanDefinitionNames()));
}
}
I am using eclipse and created this project from http://start.spring.io/ without any dependencies.
I learned that Spring create the bean of MyController class with name myController ,but Spring is not able to find myController bean
ERROR
Exception in thread "main"
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
bean named 'myController' available at
org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:686)
at
org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1210)
at
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
at
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at
org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1089)
at di.prac.DemoApplication.main(DemoApplication.java:16)
Please find and explain the error in the Project
Place your controller under sub package of di.prac like di.prac.controllers or use #ComponentScan on your controller. By default, Spring scans the current and sub packages where your main application is present. If you want to scan other packages too, then you can specify the packages in #SpringBootApplication as an argument like.
#SpringBootApplication(scanBasePackages = {"com.xyz.controllers", "com.abc.models""})
We should avoid putting the #Configuration class in the default package (i.e. by not specifying the package at all). In this case, Spring scans all the classes in all jars in a classpath. That causes errors and the application probably doesn't start.
For your controller to be available in the context of Spring, you need to define that it is managed by the Spring container. Only the #Controller annotation is not enough, it indicates only the stereotype of your bean, as well as the annotations #Repository and #Service.
In cases where the beans have these annotations and are managed by Spring, it is because their packages that the spring is scanning to search for them has been specified programmatically or per xml. In your case, you should annotate your DemoApplication class with 2 other annotations:
#Configuration - Allows access to spring context
#ComponentScan - Packages to be scanned by Spring
#Configuration
#ComponentScan (basePackages = {"controllers"})
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext ctx=SpringApplication.run(DemoApplication.class, args);
MyController m = (MyController)ctx.getBean("myController");
m.hello();
System.out.println(Arrays.asList(ctx.getBeanDefinitionNames()));
}
}
Just encountered same problem, solution is simple.You just (me also) created package "controllers" on the wrong place. It should be created not in java folder but under folder with name of your project. Simple but deadly mistake. Your code is written perfectly fine.

Spring Boot JPA: How do I connect multiple databases?

I currently have one database connected and it is working. I would like to connect another (and eventually 2 more) databases. How do I do so? There should be a solution using only annotations and properties files.
I read this
Profile Specific Properties
and it sort of helps but I still don't know how switch from one profile to the other in the code during runtime. I'm assuming I need to be connected to one profile at a time before I try to retrieve/persist things from different databases.
I also read this question, How to use 2 or more databases with spring?, but I dont know how it works too well/ if it will apply. I'm not using a controller class and I dont know what that does. I'm also not sure how the config class they mention in the answer actually connects to the specific DO.
This is my application.properties file: (marked out username and password but its there in my file)
hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
hibernate.show_sql=true
hibernate.format_sql=true
hibernate.default_schema=dbo
hibernate.packagesToScan=src.repositories.LMClientRepository.java
spring.jpa.generate-ddl=true
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.DefaultNamingStrategy
spring.datasource.username=***
spring.datasource.password=***
spring.datasource.url=jdbc:sqlserver://schqvsqlaod:1433;database=dbMOBClientTemp;integratedSecurity=false;
spring.datasource.testOnBorrow=true
spring.datasource.validationQuery=SELECT 1
spring.jpa.database=dbMOBClientTemp
spring.jpa.show-sql=true
spring.jpa.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
This is my application file:
package testApplication;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.orm.jpa.EntityScan;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import fileRetrieval.InputFileParse;
import lmDataObjects.LMClientDO;
import lmDataObjects.LoadMethodDO;
import repositories.LMClientRepository;
import repositories.LoadMethodRepository;
#SpringBootApplication
#EnableJpaRepositories(basePackageClasses = LoadMethodRepository.class)
#EntityScan(basePackageClasses = LoadMethodDO.class)
#EnableCaching
public class Application {
private static final Logger log = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public CommandLineRunner demo(LoadMethodRepository lm_repo, LMClientRepository lmc_repo) {
return (args) -> {
List<LMClientDO> lmlist = InputFileParse.getMultiGroupfile();
List<String> uniqueMediaIds = new ArrayList(InputFileParse.getUniqueMediaIds());
for (int i = 0; i < InputFileParse.getUniqueMediaIds().size(); i ++){
lm_repo.save(new LoadMethodDO(uniqueMediaIds.get(i)));
}
for (int i = 0; i < lmlist.size(); i++){
lmc_repo.save(new LMClientDO(lmlist.get(i).getClientId(), lmlist.get(i).getMediaId()));
}
//Here is where I would like to do stuff with data from the other database that I have not connected yet
};
}
}
I also made a new properties file called application-MTS.properties and I put data for the new database in there. Still unsure of what to do with it.
spring.datasource.username=***
spring.datasource.password=***
spring.datasource.url=jdbc:sqlserver://SCHQVSQLCON2\VSPD:1433;database=dbMTS;integratedSecurity=false;
You will need to define multiple DataSource beans that each represent the various database connection resources you plan to use.
You will then need to add a TransactionManager and EntityManagerFactory bean definition for each of those DataSource beans.
If you intend to have each DataSource participate in a JTA transaction, you'll need to also consider configuring a JTA transaction manager rather than individual resource local transaction managers.

Categories

Resources