Could not locate cfg.xml resource with hibernate.5.2.2.Final + spring.4.0.6.RELEASE in IDEA 2018.1 - spring

I upgraded my Idea from 2017.1 to 2018.1 and I have a Hibernate issue I can't solve... I've searched and it seems there are many problems with this but couldn't figure out what's the solution.
So, I'm using hibernate.version 5.2.2.Final, spring.version 4.0.6.RELEASE, my hibernate.cfg.xml is in src\main\resources folder and in my HibernateUtils I had something like this:
public class HibernateUtils {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// Create the ServiceRegistry from hibernate.cfg.xml
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
.configure("hibernate.cfg.xml").build();
// Create a metadata sources using the specified service registry.
Metadata metadata = new MetadataSources(serviceRegistry).getMetadataBuilder().build();
return metadata.getSessionFactoryBuilder().build();
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void shutdown() {
// Close caches and connection pools
getSessionFactory().close();
}
}
And this was working until I upgraded my IDEA. Now I have some
Caused by: java.lang.ExceptionInInitializerError
at org.mgo.HibernateUtils.buildSessionFactory(HibernateUtils.java:34)
at org.mgo.HibernateUtils.getSessionFactory(HibernateUtils.java:11)
Caused by: org.hibernate.internal.util.config.ConfigurationException: Could not locate cfg.xml resource [/main/resources/hibernate.cfg.xml]
I tried everything I found with this error, to put the hibernate.cfg.xml directly into src folder, to point the path to the xml file like "/resources/hibernate.cfg.xml" or "/main/resources/hibernate.cfg.xml", or to leave it empty like this .configure() but nothing seems to work.
I found in here: https://github.com/spring-projects/spring-framework/issues/21340
something that it doesn't works with Spring 4.3.17.RELEASE + Hibernate 5.2.17.Final and works with Spring 5.0.6.RELEASE + Hibernate 5.1.14.Final but if I change like this I get many other errors and I don't get it why my hibernate.5.2.2.Final + spring.4.0.6.RELEASE doesn't works anymore because of my IDEA. As I am using Maven, I tried to compile outside of Idea but facing the same error...

huh, maybe this will help somebody... I did it without an hibernate.cfg.xml, like this: https://dzone.com/articles/hibernate-5-java-configuration-example
public class HibernateUtils {
private static SessionFactory sessionFactory;
public static SessionFactory getSessionFactory() {
if (null == sessionFactory) {
try {
Configuration configuration = new Configuration();
// Hibernate settings equivalent to hibernate.cfg.xml's properties
Properties settings = new Properties();
settings.put(Environment.DRIVER, "com.microsoft.sqlserver.jdbc.SQLServerDriver");
settings.put(Environment.URL, "jdbc:sqlserver://localhost;databaseName=DBA;instance=SQLEXPRESS");
settings.put(Environment.USER, "user");
settings.put(Environment.PASS, "xxx");
settings.put(Environment.DIALECT, "org.hibernate.dialect.SQLServerDialect");
settings.put(Environment.SHOW_SQL, "true");
settings.put(Environment.CURRENT_SESSION_CONTEXT_CLASS, "thread");
configuration.setProperties(settings);
configuration.addAnnotatedClass(MyClass1.class);
configuration.addAnnotatedClass(MyClass2.class);
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties()).build();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (Exception e) {
e.printStackTrace();
}
}
return sessionFactory;
}
}

Related

Hibernate SessionFactory not getting created due to inability to locate the my.hbm.xml files by mappingResource, see the screenshots

#Configuration class having one of the #bean declaration for hibernate SessionFactory. its mappingResource("hbm file path") method is not locating my.hbm.xml and hence getting "cannot be opened because it does not exists." I applied many strategies but no luck any help will be appreciated. For clear exposure, added screenshots as well.
#Bean
public SessionFactory hibernateSessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource (dataSource());
sessionFactory.setLobHandler(lobHandler());
List<String> mappingResources = new ArrayList<>();
mappingResources.add("hibernate/Customer RequestDTO.hbm.xml");
mappingResources.add("hibernate/AccessRequestDTO.hbm.xml");
mappingResources.add("hibernate/AccessRequestItemDTO.hbm.xml");
sessionFactory.setMappingResources (mapping Resources.toArray(new String[mappingResources.size()]));
sessionFactory.setHibernate Properties (hibernateProperties());
try {
sessionFactory.after PropertiesSet();
} catch (java.lang. Exception e) {
LOG.error("Error creating Session Facotry", e);
}
return (SessionFactory) sessionFactory.getObject();
}
Issue : java.io.FileNotFoundException : Class Path Resource [CutomerRequestDTO.hbm.xml] cannot be opened because it does not exists.
Thanks in Advance!!!

what the difference between the two codes (Spring Boot)?

These two codes should do exactly the same thing, but the first one works and the second one doesnt work. Can anyone review the code and give the details about why the code failed during second approach.
The first code :
#Component
public class AdminSqlUtil implements SqlUtil {
#Autowired private ApplicationContext context;
DataSource dataSource =(DataSource) context.getBean("adminDataSource");
public void runSqlFile(String SQLFileName) {
Resource resource = context.getResource(SQLFileName);
EncodedResource encodedResource = new EncodedResource(resource, Charset.forName("UTF-8"));
try {
ScriptUtils.executeSqlScript(dataSource.getConnection(), encodedResource);
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
}
The second code :
#Component
public class AdminSqlUtil implements SqlUtil {
#Autowired private ApplicationContext context;
public void runSqlFile(String SQLFileName) {
Resource resource = context.getResource(SQLFileName);
EncodedResource encodedResource = new EncodedResource(resource, Charset.forName("UTF-8"));
try {
ScriptUtils.executeSqlScript((DataSource)context.getBean("adminDataSource").getConnection(), encodedResource);
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
}
The first one has a private scope and the framework can not access it. You could have add #inject before your private scope variable so the framework can initialize it. However the best practice is to define a public dependency setter for that to work.
The second one on the other hand initiates the value at the start, which is not a dependency injection by the way. I am not talking about good and bad practice. It is wrong. We don’t initialize a variable which is suppose to be initialized by the framework.
So lets go with the first one, Try to add a setter for it.
Take a look at this link.

java.lang.NullPointerException: When saving jpa data using Gemfire cachewriter

Jpa Repository save is working in all classes. But when trying to save in CacheWriter it is throwing NullPointerException(personRepository.save(entryEvent.getNewValue())). Any idea on this? Configured mysql database in application properties.
java.lang.NullPointerException
at com.javasampleapproach.gemfirerestapi.GemfireWriter.beforeCreate(GemfireWriter.java:28)
at com.gemstone.gemfire.internal.cache.LocalRegion.cacheWriteBeforePut(LocalRegion.java:3131)
at com.gemstone.gemfire.internal.cache.AbstractRegionMap.invokeCacheWriter(AbstractRegionMap.java:3145)
at com.gemstone.gemfire.internal.cache.AbstractRegionMap.basicPut(AbstractRegionMap.java:2909)
at com.gemstone.gemfire.internal.cache.LocalRegion.virtualPut(LocalRegion.java:5821)
at com.gemstone.gemfire.internal.cache.LocalRegionDataView.putEntry(LocalRegionDataView.java:118)
at com.gemstone.gemfire.internal.cache.LocalRegion.basicPut(LocalRegion.java:5211)
at com.gemstone.gemfire.internal.cache.LocalRegion.validatedPut(LocalRegion.java:1597)
at com.gemstone.gemfire.internal.cache.LocalRegion.put(LocalRegion.java:1580)
at com.gemstone.gemfire.internal.cache.AbstractRegion.put(AbstractRegion.java:327)
Controller:
#GetMapping(value = "/getPerson")
public Iterable<Person> getPerson(#RequestParam("id") long personId,#RequestParam("age") int age, #RequestParam("name") String name) {
try{
Person bob = new Person();
bob.setPersonId(personId);
bob.setAge(age);
bob.setName(name);
Region<Long,Person> region=gemfireCache.getRegion("person");
region.put(personId, bob);
}catch(Exception e){
e.printStackTrace();
}
return personRepository.findAll();
}
Cachewriter:
public class GemfireCacheWriter implements CacheWriter<Long, Person>{
#Autowired
PersonRepository personRepository;
#Override
public void beforeCreate(EntryEvent<Long, Person> entryEvent) throws CacheWriterException {
// TODO Auto-generated method stub
personRepository.save(entryEvent.getNewValue());
}
}
CacheWriter Config:
#Bean
LocalRegionFactoryBean<Long, Person> personRegion(final GemFireCache cache) {
LocalRegionFactoryBean<Long, Person> personRegion = new LocalRegionFactoryBean<>();
personRegion.setCache(cache);
personRegion.setName("person");
personRegion.setPersistent(false);
personRegion.setCacheWriter(new GemfireWriter());
personRegion.setCacheLoader(new GemfireLoader());
return personRegion;
}
Looking at the source code for LocalRegion, I don't think the entryEvent received by your CacheWriter could be null, so the actual null reference is probably personRepository. Have you correctly configured spring-data-gemfire to autowire the PersonRepository?, is the CacheWriter configured as a Spring bean (using the #Component as an example)?.
You can use the Write Through Example as a good starting point for implementing this use case.
Hope this helps. Cheers.

InstanceNotFoundException when trying to get Activemq MBean

I have the following configuration:
#Configuration
public class ConfigureRMI {
#Value("${jmx.rmi.host:localhost}")
private String rmiHost;
#Value("${jmx.rmi.port:1099}")
private Integer rmiPort;
#Bean
public RmiRegistryFactoryBean rmiRegistry() {
final RmiRegistryFactoryBean rmiRegistryFactoryBean = new RmiRegistryFactoryBean();
rmiRegistryFactoryBean.setPort(rmiPort);
rmiRegistryFactoryBean.setAlwaysCreate(true);
return rmiRegistryFactoryBean;
}
#Bean
#DependsOn("rmiRegistry")
public ConnectorServerFactoryBean connectorServerFactoryBean() throws Exception {
final ConnectorServerFactoryBean connectorServerFactoryBean = new ConnectorServerFactoryBean();
connectorServerFactoryBean.setObjectName("connector:name=rmi");
connectorServerFactoryBean.setServiceUrl(String.format("service:jmx:rmi://%s:%s/jndi/rmi://%s:%s/jmxrmi", rmiHost, rmiPort, rmiHost, rmiPort));
return connectorServerFactoryBean;
}
#Bean
#DependsOn("connectorServerFactoryBean")
public DestinationViewMBean queueMonitor() {
JMXConnectorServer connector = null;
MBeanServerConnection connection;
ObjectName nameConsumers;
try {
connector = connectorServerFactoryBean().getObject();
connection = connector.getMBeanServer();
nameConsumers = new ObjectName("org.apache.activemq:type=Broker,brokerName=localhost,destinationType=Queue,destinationName=tasks");
} catch (Exception e) {
e.printStackTrace();
return null;
}
DestinationViewMBean mbView = MBeanServerInvocationHandler.newProxyInstance(connection, nameConsumers, DestinationViewMBean.class, true);
return mbView;
}
}
It configures and instantiates DestinationViewMBean that I try to use later in code like this:
Long queueSize = queueMonitor.getQueueSize();
But it throws an exception javax.management.InstanceNotFoundException: org.apache.activemq:type=Broker,brokerName=localhost,destinationType=Queue,destinationName=tasks
I'm sure the names are as I typed. I can see the brocker name and tasks queue in ActiveMQ web console, elements are queued and dequeued as intended. But I cant't monitor the queue size. The method I used (the one I provided) was made from many answers here on SO and man pages on JMX and ActiveMQ.
I'm wondering if I'm missing something obvious. I turned firewall down, I'm on localhost. Why can't DestinationViewMBean find the queue?
UPD: I used JConsole to check the MBean name. I managed to fix InstanceNotFoundException but now I can't get any attribute from the bean. I've tried a lot of them in debugger (just run throught the attributes I could find in DestinationViewMBean interface). But on every try of attribute getter I get javax.management.AttributeNotFoundException: getAttribute failed: ModelMBeanAttributeInfo not found for QueueSize (or any other attribute).

Spring, autowire #Value from a database

I am using a properties File to store some configuration properties, that are accessed this way:
#Value("#{configuration.path_file}")
private String pathFile;
Is it possible (with Spring 3) to use the same #Value annotation, but loading the properties from a database instead of a file ?
Assuming you have a table in your database stored key/value pairs:
Define a new bean "applicationProperties" - psuedo-code follows...
public class ApplicationProperties {
#AutoWired
private DataSource datasource;
public getPropertyValue(String key) {
// transact on your datasource here to fetch value for key
// SNIPPED
}
}
Inject this bean where required in your application. If you already have a dao/service layer then you would just make use of that.
Yes, you can keep your #Value annotation, and use the database source with the help of EnvironmentPostProcessor.
As of Spring Boot 1.3, we're able to use the EnvironmentPostProcessor to customize the application's Environment before application context is refreshed.
For example, create a class which implements EnvironmentPostProcessor:
public class ReadDbPropertiesPostProcessor implements EnvironmentPostProcessor {
private static final String PROPERTY_SOURCE_NAME = "databaseProperties";
private String[] CONFIGS = {
"app.version"
// list your properties here
};
#Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
Map<String, Object> propertySource = new HashMap<>();
try {
// the following db connections properties must be defined in application.properties
DataSource ds = DataSourceBuilder
.create()
.username(environment.getProperty("spring.datasource.username"))
.password(environment.getProperty("spring.datasource.password"))
.url(environment.getProperty("spring.datasource.url"))
.driverClassName("com.mysql.jdbc.Driver")
.build();
try (Connection connection = ds.getConnection();
// suppose you have a config table storing the properties name/value pair
PreparedStatement preparedStatement = connection.prepareStatement("SELECT value FROM config WHERE name = ?")) {
for (int i = 0; i < CONFIGS.length; i++) {
String configName = CONFIGS[i];
preparedStatement.setString(1, configName);
ResultSet rs = preparedStatement.executeQuery();
while (rs.next()) {
propertySource.put(configName, rs.getString("value"));
}
// rs.close();
preparedStatement.clearParameters();
}
}
environment.getPropertySources().addFirst(new MapPropertySource(PROPERTY_SOURCE_NAME, propertySource));
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
Finally, don't forget to put your spring.factories in META-INF. An example:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.baeldung.environmentpostprocessor.autoconfig.PriceCalculationAutoConfig
Although not having used spring 3, I'd assume you can, if you make a bean that reads the properties from the database and exposes them with getters.

Resources