I am trying to database config dynamicly in dependence to environment.
I would like to use #Value to get database info.
My Config file is:
#Configuration
#EnableTransactionManagement
#ComponentScan(basePackages = "service")
#PropertySource("classpath:application-${environment}.properties")
#EnableJpaRepositories("repositories")
public class PersistanceConfig {
private final String MODEL_PATH = "model";
#Value("${mariadb.driver}:#{null}")
private String driver;
#Value("${mariadb.url}:#{null}")
private String url;
#Value("${mariadb.username}:#{null}")
private String username;
#Value("${mariadb.password}:#{null}")
private String password;
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] {MODEL_PATH});
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
#Bean
public DataSource dataSource(){
Assert.notNull(driver, "JBDC driver is not defined");
Assert.notNull(url, "url is not defined");
Assert.notNull(username, "username is not defined");
Assert.notNull(password, "password is not defined");
final BasicDataSource source = new BasicDataSource();
source.setDriverClassName(driver);
source.setUrl(url);
source.setUsername(username);
source.setPassword(password);
return source;
}
#Bean
public PlatformTransactionManager transactionManager(
EntityManagerFactory emf){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
properties.setProperty(
"hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
return properties;
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(){
return new PropertySourcesPlaceholderConfigurer();
}
}
During compile time is property-file properly found and variables driver, url, username and password are properly filled.
Unfortunatelly, during runtime #Value doesn't execute and fill the expression into variable (subsequent exceptions is: "Could not use '${mariadb.driver}' to connect").
According another answer here I added static PropertySourcesPlaceholderConfigurer bean, but i had no effect.
I also tried different combination of Environmnet class and PropertySource values but nothing worked.
Thank you for your advise.
Problem was pretty stupid.
I had my configurations file in root of project, not root of src java folder.
Related
I have an application running on Payara 4 using a custom GSON JSON adapter. I would like to migrate to Payara 5 (5.191) and start using JSON-B. In our current application we can control the JSON output using annotations on a resource.
For example using #Summarize:
#GET
#Path("summary/{encryptedId}")
#Produces(MediaType.APPLICATION_JSON)
#Summarize
public Address findSummarized(#PathParam("encryptedId") String encryptedId) {
return super.find(encryptedId);
}
it will cause a different GSON configuration to be used in our #Provider:
#Provider
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class GsonProvider<T> implements MessageBodyReader<T>, MessageBodyWriter<T> {
public GsonProvider() {
gson = getGson(EntityAdapter.class);
gsonSummary = getGson(EntitySummaryAdapter.class);
}
...
#Override
public void writeTo(T object,
Class<?> type,
Type genericType,
Annotation[] annotations,
MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders,
OutputStream entityStream)
throws IOException, WebApplicationException {
boolean summarize = contains(annotations, Summarize.class);
try (PrintWriter printWriter = new PrintWriter(entityStream)) {
printWriter.write((summarize ? gsonSummary : gson).toJson(object));
printWriter.flush();
}
}
}
I want to do something similar in the new JSON-B setup. I annotated our entities with #JsonbTypeSerializer(MySerializer.class), so I would like to be able to detect from within the serializer what it should do: either create a full serialized JSON object, or a summary.
What I hoped to do is set a property in the JsonbConfig, like so:
JsonbConfig config = new JsonbConfig()
.setProperty("com.myCompany.jsonb.summarize", true);
and read it in the serializer using #Context (just guessing that this might work here), like so:
#Context
private JsonbConfiguration config;
.. but that's not. Is there any way to access JAX-RS resource annotations from a JsonbSerializer?
You could accomplish a similar goal using two separate Jsonb instances in your JAX-RS provider class like so:
#Provider
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class JsonbProvider<T> implements MessageBodyReader<T>, MessageBodyWriter<T> {
private static final Jsonb jsonb = JsonbBuilder.create(new JsonbConfig()
.withAdapters(new EntityAdapter()));
private static final Jsonb jsonbSummary = JsonbBuilder.create(new JsonbConfig()
.withAdapters(new EntitySummaryAdapter()));
...
#Override
public void writeTo(T object,
Class<?> type,
Type genericType,
Annotation[] annotations,
MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders,
OutputStream entityStream)
throws IOException, WebApplicationException {
boolean summarize = contains(annotations, Summarize.class);
try (PrintWriter printWriter = new PrintWriter(entityStream)) {
printWriter.write((summarize ? jsonbSummary : jsonb).toJson(object));
printWriter.flush();
}
}
}
In the end I opted to create summaries from within my entities and drop the annotation on my REST resources. It was a bit of work, but I think it has been worth it.
I created a Summarizable interface and added a default method there to create a simple map summary of any entity, based on a extended version of the PropertyVisibilityStrategy we created for the full version of the entities.
public interface Summarizable {
public default Map<String, Object> toSummary() {
SummaryPropertyVisibilityStrategy summaryStrategy = new SummaryPropertyVisibilityStrategy();
Map<String, Object> summary = new LinkedHashMap<>();
ReflectionUtils.getFields(this.getClass())
.stream()
.filter(summaryStrategy::isVisible)
.map(f -> new AbstractMap.SimpleEntry<>(f.getName(), summarize(f)))
.filter(e -> e.getValue() != null)
.forEach(e -> summary.put(e.getKey(), e.getValue()));
return summary;
}
public default Object summarize(final Field field) {
Object value = ReflectionUtils.getValueJsonb(this, field);
return value != null && Stream.of(ManyToOne.class, OneToOne.class).anyMatch(field::isAnnotationPresent)
? value.toString()
: value;
}
}
public static Object getValueJsonb(final Object object, final Field field) {
field.setAccessible(true);
JsonbTypeAdapter adapterAnnotation = field.getAnnotation(JsonbTypeAdapter.class);
try {
Object value = field.get(object);
return adapterAnnotation == null
? value
: adapterAnnotation.value().newInstance().adaptToJson(value);
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
Config client is unable to fetch the changed property values from the modified property files in Git. I need assistance in resolving this issue.
I created a new spring config server and client. Initially the values from the property files were fetched properly. When i changed the values in the property file, the client was still returning old values. I tried POSTing to http://localhost:8080/actuator/refresh and even after that, the old values are returned. Finally i deleted the property file from the git repository and the client still returns old values.
Config Server bootstrap.properties
spring.application.name=ConfigServer
server.port=8888
encrypt.key=123456
spring.security.user.password=configpassword123
spring.cloud.config.server.git.uri=https://some-repository/ConfigRepo.git
spring.cloud.config.server.git.username=git_user
spring.cloud.config.server.git.password=git_password
ConfigServer.java
#Configuration
#EnableDiscoveryClient
#SpringBootApplication
#EnableConfigServer
public class ConfigServer {
public static void main(String[] args) {
SpringApplication.run(ConfigServer.class, args);
}
}
WebSecurityConfiguration.java
#Configuration
#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.anyRequest().authenticated().and().httpBasic();
}
}
Config Client bootstrap.properties
spring.application.name=config-client
spring.cloud.config.uri=http://config-server:8888
spring.cloud.config.username=user
spring.cloud.config.password=configpassword123
management.endpoints.web.exposure.include=*
Config Client Controller Class
#RefreshScope
#RestController
public class ConfigController {
#Value("${applicationname}")
private String appName;
#Value("${username}")
private String username;
#Value("${password}")
private String password;
#Value("${instancename}")
private String environment;
#Value("${dbconnection}")
private String dbConnection;
#GetMapping("/user")
public String getUser() {
return "Application: "+ appName +" Instance: "+ environment + " User: " + username + " / " + password;
}
#GetMapping("/dbconn")
public String getDBConnection() {
return dbConnection;
}
}
Please check whether your post refresh request works fine. You need to permit the POST request in security configuration.
Reference code :
http.antMatchers(HttpMethod.POST, "/refresh").permitAll();
When trying to use #AutoWire feature with one of StandAlone Application unable to do so instead getting Null Pointer Exception. Please highlight my mistakes if any. Your help is appreciated.
Spring Ver 5.1.5.RELEASE and we're not using any xml config file to tell spring there are annotated classes to look into instead using #ComponentScan or #EnableAutoConfiguration at the top of AppConfig and boost strap the Context from main() class as a first line. But Autowiring works perfectly with internal bean/java classes of jdk(Environment) but not with custom POJO classes. If we're trying to get through getBean method then it works. But I'm trying to avoid creating context everywhere and using getBean() Please Refer below and help me only with your valuable guidelines.
public class ContextMaster {
private static AnnotationConfigApplicationContext appContext;
public static AnnotationConfigApplicationContext getApplicationContext() {
if (appContext == null) {
appContext = new AnnotationConfigApplicationContext(ContextConfig.class);
//appContext = new AnnotationConfigApplicationContext("com.xx.xx.xxx","xx.xxx.xxxx.xxx.datamanager");
logger.debug("Context Invoked !!");
}
return appContext;
}
}
#Configuration
#EnableAutoConfiguration
#PropertySource("classpath:db.properties")
#EnableTransactionManagement
#ComponentScans(value = {
#ComponentScan(basePackages = "xxxxx.datamanager"),
#ComponentScan(basePackages = "com.xx.xx.xxx"),
#ComponentScan(basePackages = "com.xx.xx.xxx.utils")})
public class AppConfig {
#Autowired
private Environment env;
#Bean
public DataSource getDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(env.getProperty("db.driver"));
dataSource.setUrl(env.getProperty("db.url"));
return dataSource;
}
#Bean
public LocalSessionFactoryBean getSessionFactory() {
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
//LocalSessionFactoryBean sessionFactoryBean = new AnnotationSessionFactoryBean();
factoryBean.setDataSource(getDataSource());
Properties props=new Properties();
props.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
props.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
props.put("hibernate.cache.region.factory_class", env.getProperty("hibernate.cache.region.factory_class"));
factoryBean.setHibernateProperties(props);
factoryBean.setAnnotatedClasses(xx.class, xxxx.class, xxxx.class, xxx.class);
return factoryBean;
}
#Bean
public HibernateTransactionManager getTransactionManager() {
return transactionManager;
}
}
// Here is NPE thrown when tried with auto-configured bean
#Component
public class Good extends Good11 {
#Autowired
private RxxxDyyyyHelper rdh;
//RxxxDyyyyHelper rdh =
ContextHelper.getApplicationContext().getBean(RxxxDyyyyHelper .class);
rdh.setProperty(); // NPE here
rdh.getProperty(); // NPE
}
// Here we're trying to initiate the LosUtils class
public class LosUtils {
public static void main(String args[]) throws Exception {
AnnotationConfigApplicationContext applicationContext = `ContextHelper.getApplicationContext();`
}
It seems like you didn't put the full code here, because your Good class won't compile this way..
How do I get activejdbc working with a HikariCP connection pool? Mostly want this for documentation purposes.
I've tried a few different methods but none have worked so far.
Figured it out for postrgresql:
public static final HikariConfig hikariConfig() {
HikariConfig hc = new HikariConfig();
hc.setDataSourceClassName("org.postgresql.ds.PGSimpleDataSource");
hc.setJdbcUrl(DataSources.PROPERTIES.getProperty("jdbc.url"));
hc.setUsername(DataSources.PROPERTIES.getProperty("jdbc.username"));
hc.setPassword(DataSources.PROPERTIES.getProperty("jdbc.password"));
hc.setMaximumPoolSize(10);
return hc;
}
public static final HikariDataSource hikariDataSource = new HikariDataSource(hikariConfig());
public static final void dbInit() {
Base.open(hikariDataSource); // get connection from pool
}
public static final void dbClose() {
Base.close();
}
When I add a property in the application.properties files, this can be access from the main class without any problem.
#SpringBootApplication
#ComponentScan(basePackages = "com.example.*")
public class MailTestApplication implements CommandLineRunner {
#Value("${admin.mail}")
String email;
public static void main(String[] args) {
SpringApplication.run(MailTestApplication.class, args);
}
#Override
public void run(String... strings) throws Exception {
System.out.println(email);
Email email = new Email();
email.sendMail();
}
}
However, when I try to access it from any other class it is never retrieved.
#Component
public class Email {
#Autowired
private MailSender sender;
#Value("${admin.mail}")
String email;
public Email() {
}
public void sendMail() {
SimpleMailMessage msg = new SimpleMailMessage();
System.out.println(email);
msg.setTo("sample#email.com");
msg.setSubject("Send mail by Spring Boot");
msg.setText("Send mail by Spring Boot");
sender.send(msg);
}
}
I was reading some of the previous questions other users posted without a clear result for me. I even tried to find some examples with similar resutl.
Could someone give me any clue about this?
Thanks a lot in advance.
The #Value should work (Im asuming your class is under the com.example.* package since you are scanning that package) but if you want to do it another way this is what im using :
public class JpaConfiguration {
public static final String TRANSACTION_MANAGER_NAME = "jpaTransactionManager";
#Autowired
Environment applicationProperties;
Then to use it
#Bean
public DriverManagerDataSource driverManagerDataSource() {
DriverManagerDataSource driverConfig = new DriverManagerDataSource();
driverConfig.setDriverClassName(applicationProperties.getProperty("data.jpa.driverClass"));
driverConfig.setUrl(applicationProperties
.getProperty("data.jpa.connection.url"));
driverConfig.setUsername(applicationProperties
.getProperty("data.jpa.username"));
driverConfig.setPassword(applicationProperties
.getProperty("data.jpa.password"));
return driverConfig;
}
UPDATE AFTER GETTING THE GITHUB REPO
I Don't really know what you are trying to build but :
If you do this:
#Override
public void run(String... strings) throws Exception {
//System.out.println(email);
Email email = new Email();
email.sendMail();
}
Then you are creating the instance of the class, and not spring. so you shouldn't be creating the instance yourself there it should be spring.
That said, i dont know if you are creating a web application a command line application or both.
That said ill give you a minor solution to show you that the dependency injection is in fact working.
1_ add a getter to your email on email class. remove the CommandLine interface (If you want to implement this i would recomend you to put CommandLine implmentations on another package say Controller);
And then run your app like this:
#SpringBootApplication
#ComponentScan(basePackages = "com.example")
public class MailTestApplication {
#Value("${admin.mail}")
String email;
public static void main(String[] args) {
// SpringApplication.run(MailTestApplication.class, args);
final ConfigurableApplicationContext context = new SpringApplicationBuilder(MailTestApplication.class).run(args);
Email e = context.getBean(Email.class);
System.out.println(e.getEmail());
}
The Key thing I want to show is that the instance is created by spring thats why the wiring works. and the email gets printed in the console.
Regarding the email class :
#Component
public class Email {
// #Autowired
// private MailSender sender;
#Value("${admin.mail}")
String email;
public Email() {
}
public void sendMail() {
SimpleMailMessage msg = new SimpleMailMessage();
System.out.println(email);
msg.setTo("sample#email.com");
msg.setSubject("Send mail by Spring Boot");
msg.setText("Send mail by Spring Boot");
// sender.send(msg);
}
public String getEmail() {
return email;
}
}
I Comment out the MailSender since I think you need to configure that too, i have made a custom mailSender that uses gmail and other for mailChimp that i can share with you if you need. but again I dont really know what your intent with the app is.
Hope the info helps you.