I have an env variable $MONGODB_URI
echo $MONGODB_URI
mongodb://localhost:27017
My application.properties
mongoUri=${MONGODB_URI}
My Config.java
#Configuration
public class Config {
#Value("${mongoUri}")
private String mongoUri;
..
}
When I try to start up the app in IntelliJ Idea, I get
Could not resolve placeholder 'MONGODB_URI' in value "${MONGODB_URI}"
The app starts up fine with
./gradlew bootRun
How can I properly configure IntelliJ to read from the environment? I'll need to swap out the db url depending on if it's prod, local, etc.
You need to run to your application with environment configuration as shown below in image:
sample code to verify
#RestController
public class StatusController {
private final Environment environment;
public StatusController(Environment environment) {
this.environment = environment;
}
#GetMapping("/env")
public String envValue() {
return environment.getProperty("MONGODB_URI");
}
}
Related
I'm trying to override configuration properties via environment variables on Quarkus application, compiled and dockerized with native profile.
When I exec into my container, and check the environment variables, I can confirm that the value I expect is there.
In my quarkus app, I have a bean which will log the config properties at startup.
#ApplicationScoped
public class AppLifecycleBean {
#Inject
Configuration configuration;
void onStart(#Observes StartupEvent ev) {
System.out.println("The application is starting...");
System.out.println(configuration.toString());
}
void onStop(#Observes ShutdownEvent ev) {
System.out.println("The application is stopping...");
}
}
The Configuration class looks like this.
#Singleton
public class Configuration {
#ConfigProperty(name = "quarkus.profile")
public String quarkusProfile;
...
#Override
public String toString() {
return "Configuration:\n" +
"quarkusProfile='" + quarkusProfile + "'\n" +
...
}
}
Deploying with Kubernetes, I pass a value for env var QUARKUS_PROFILE of 'FR2', but I still get prod. Is it not possible to override config properties via environment variables with native images ?
Executing a simple unit test over a Mongo Repository fails in Windows 10 due to
java.io.IOException: Cannot run program
"C:\Users\myuser\AppData\Local\Temp\extract-88ea18ed-75d4-420f-be7f-623baeeb5c70extractmongod.exe":
CreateProcess error=1260, This program is blocked by group policy. For
more information, contact your system administrator
This had worked until a few days ago, but failing now probably due to some recent Windows update.
Example of a failing test
#ExtendWith(SpringExtension.class)
#DataMongoTest
#AutoConfigureDataJpa
#AutoConfigureTestDatabase
#ExtendWith(LogbackSuppressorExtension.class)
#Import(TestConfiguration.class)
class AnnexContentRepositoryTest {
#Autowired
private MongoTemplate mongoTemplate;
#Autowired
private AnnexContentRepository annexContentRepository;
#Test
public void findAllByParentCodeAndParentType() {
AnnexContent annexContent = addAnnexContent();
Page<AnnexContent> annexContentResult = annexContentRepository
.findAllByParentCodeAndParentType(annexContent.getParentCode(), ParentType.THE_ONE,
Pageable.unpaged());
Assertions.assertEquals(1, annexContentResult.getTotalElements());
}
private AnnexContent addAnnexContent() {
AnnexContent annexContent = AnnexContentBuilder.buildDefault();
return mongoTemplate.save(annexContent);
}
}
The solution that I've found is to add two system variables that embedded mongo reads ("de.flapdoodle.embed.io.tmpdir" and "EMBEDDED_MONGO_ARTIFACTS") in test configuration (the same applies in running the application with embedded mongo, where these two system variables can be set also).
#Configuration
public class TestConfiguration {
public TestConfiguration(Environment environment) {
if (SystemUtils.IS_OS_WINDOWS) {
System.setProperty("de.flapdoodle.embed.io.tmpdir", environment.getProperty("mongo-embedded.windows.temp-dir"));
System.setProperty("EMBEDDED_MONGO_ARTIFACTS", environment.getProperty("mongo-embedded.windows.temp-dir"));
}
}
}
By changing the location from the embedded mongo default ("c:\myuser\appdata\local\temp") to, for example, "c:\temp", the problem disappears.
Pringi's solution works. Here it is, simplified with an actual Windows path in c:\temp\mongotemp
First manually create directory c:\temp\mongotemp
Add a new MongoConfig.java file:
import org.apache.commons.lang3.SystemUtils;
import org.springframework.context.annotation.Configuration;
#Configuration
public class MongoConfig {
public MongoConfig() {
if (SystemUtils.IS_OS_WINDOWS) {
System.setProperty("de.flapdoodle.embed.io.tmpdir", "c:\\temp\\mongotemp");
}
}
}
App should run now.
You can then inspect the contents of c:\temp\mongotemp , it's the executable that was previously being blocked by the system policy.
I am using posgresql testcontainer in springboottest. As I have multiple tests involving this testcontainer, hence I have used static testcontainer which will be invoked once for all tests of 1 junit class and shutdown after all tests are executed.
This I have implemented using ParameterResolver, BeforeEachCallback.
Problem with this approach is that datasource metadata like jdbc-url, db name , host , port configured in default application.yml is not used directly in testcontainer properties, instead I have hardcoded those values because springboot properties are not available at that time.
is there any better approach where I can use static testcontainers having BeforeEachCallback feature whose values are fetched from default application.yml ?
#SpringBootTest
class SampleTest extends TestContainerBase {
#Test
void test1() {
//some code
}
}
#ExtendWith(ContainerExtension.class)
#ResourceLock(Environment.ID)
public abstract class TestContainerBase {
protected static String jdbcUrl;
protected static String username;
protected static String password;
#BeforeAll
static void prepareContainerEnvironment(Environment env) {
jdbcUrl = env.getJdbcUrl();
username = env.getUsername();
password = env.getPassword();
}
#DynamicPropertySource
static void dynamicPropertySource(DynamicPropertyRegistry registry) {
registry.add("spring.datasource-.jdbc-url", () -> jdbcUrl);
registry.add("spring.datasource-.username", () -> username);
registry.add("spring.datasource-.password", () -> password);
registry.add("spring.datasource-.driver-class-name", () -> "org.postgresql.Driver");
}
}
public class ContainerExtension implements ParameterResolver, BeforeEachCallback {
// overridden supportsParameter and resolveParameter
}
I want that myDB , sa , sa are read from application.yml. How can I get application.yml values here in this class ? As springboot context is not yet loaded so I am unable to think of any alternative to get those values.
public class ContainerResource extends Environment {
#Container
protected static PostgreSQLContainer postgreSQLContainer =
new PostgreSQLContainer("artifactory.devtools.syd.c1.macquarie.com:9996/postgres:11")
.withDatabaseName("myDB")
.withUsername("username")
.withPassword("password");
ContainerEnvironmentResource() {
postgreSQLContainer.start();
this.setJdbcUrl(postgreSQLContainer.getJdbcUrl());
this.setUsername(postgreSQLContainer.getUsername());
this.setPassword(postgreSQLContainer.getPassword());
}
}
It looks like there is now a dedicated project just to integrate Testcontainers and Spring-Boot. As I understand the documentation it should be transparent to the code as everything is done using Spring magic.
https://github.com/Playtika/testcontainers-spring-boot
I have 2 issues trying to connect to dynamodb in aws. It's working locally:
#Configuration
class DynamoDbConfig {
#Value("${amazon.access.key}")
private String awsAccessKey;
#Value("${amazon.access.secret.key}")
private String awsSecretKey;
#Value("${amazon.dynamodb.endpoint}")
private String awsDynamoDBEndPoint;
#Value("${amazon.dynamodb.region}")
private String awsDynamoDBRegion;
#Bean
public AWSCredentials amazonAWSCredentials() {
return new BasicAWSCredentials(awsAccessKey, awsSecretKey);
}
public AWSCredentialsProvider amazonAWSCredentialsProvider() {
return new AWSStaticCredentialsProvider(amazonAWSCredentials());
}
#Bean
public DynamoDB dynamoDB() {
AmazonDynamoDB amazonDynamoDB = AmazonDynamoDBClientBuilder.standard()
.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(awsDynamoDBEndPoint, awsDynamoDBRegion))
.withCredentials(amazonAWSCredentialsProvider())
.build();
return new DynamoDB(amazonDynamoDB);
}
}
application-local.properties
amazon.access.key=key1
amazon.access.secret.key=key2
amazon.dynamodb.endpoint=http://localhost:8000
amazon.dynamodb.region=us-east-1
application-prod.properties
amazon.access.key=${AWS_ACCESS_KEY_ID}
amazon.access.secret.key=${AWS_SECRET_ACCESS_KEY}
amazon.dynamodb.endpoint=dynamodb.us-east-1.amazonaws.com
amazon.dynamodb.region=${AWS_DEFAULT_REGION}
I already got credentials and my .aws/credentials looks good:
[default]
aws_access_key_id = MyKeyId
aws_secret_access_key = MySecretKey
aws_session_token = blablabla
disney_session_expiration = This is also ok
1 Issue) It looks like always take the application-local.properties profile, if I show the awsAccessKey and awsSecretKey in the class DynamoDbConfig, I get key1 and key2. I tried with these 2 commands:
mvn spring-boot:run -Dspring.profiles.active=prod
mvn spring-boot:run -Pprod
2 Issue) I renamed application-prod.properties as application.properties to make spring takes that config file and I get this error message:
Could not resolve placeholder 'AWS_SECRET_ACCESS_KEY' in value "${AWS_SECRET_ACCESS_KEY}"
I guess the profile is not an issue, the values are not set/defined for the following keys
${AWS_ACCESS_KEY_ID}
${AWS_SECRET_ACCESS_KEY}
${AWS_DEFAULT_REGION}
Being new to Spring Boot I am wondering on how I can configure connection details for MongoDB.
I have tried the normal examples but none covers the connection details.
I want to specify the database that is going to be used and the url/port of the host that runs MongoDB.
Any hints or tips?
Just to quote Boot Docs:
You can set spring.data.mongodb.uri property to change the url, or alternatively specify a host/port. For example, you might declare the following in your application.properties:
spring.data.mongodb.host=mongoserver
spring.data.mongodb.port=27017
All available options for spring.data.mongodb prefix are fields of MongoProperties:
private String host;
private int port = DBPort.PORT;
private String uri = "mongodb://localhost/test";
private String database;
private String gridFsDatabase;
private String username;
private char[] password;
It's also important to note that MongoDB has the concept of "authentication database", which can be different than the database you are connecting to. For example, if you use the official Docker image for Mongo and specify the environment variables MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD, a user will be created on 'admin' database, which is probably not the database you want to use. In this case, you should specify parameters accordingly on your application.properties file using:
spring.data.mongodb.host=127.0.0.1
spring.data.mongodb.port=27017
spring.data.mongodb.authentication-database=admin
spring.data.mongodb.username=<username specified on MONGO_INITDB_ROOT_USERNAME>
spring.data.mongodb.password=<password specified on MONGO_INITDB_ROOT_PASSWORD>
spring.data.mongodb.database=<the db you want to use>
spring.data.mongodb.host and spring.data.mongodb.port are not supported if you’re using the Mongo 3.0 Java driver. In such cases, spring.data.mongodb.uri should be used to provide all of the configuration, like this:
spring.data.mongodb.uri=mongodb://user:secret#mongo1.example.com:12345
In a maven project create a file src/main/resources/application.yml with the following content:
spring.profiles: integration
# use local or embedded mongodb at localhost:27017
---
spring.profiles: production
spring.data.mongodb.uri: mongodb://<user>:<passwd>#<host>:<port>/<dbname>
Spring Boot will automatically use this file to configure your application. Then you can start your spring boot application either with the integration profile (and use your local MongoDB)
java -jar -Dspring.profiles.active=integration your-app.jar
or with the production profile (and use your production MongoDB)
java -jar -Dspring.profiles.active=production your-app.jar
You can define more details by extending AbstractMongoConfiguration.
#Configuration
#EnableMongoRepositories("demo.mongo.model")
public class SpringMongoConfig extends AbstractMongoConfiguration {
#Value("${spring.profiles.active}")
private String profileActive;
#Value("${spring.application.name}")
private String proAppName;
#Value("${spring.data.mongodb.host}")
private String mongoHost;
#Value("${spring.data.mongodb.port}")
private String mongoPort;
#Value("${spring.data.mongodb.database}")
private String mongoDB;
#Override
public MongoMappingContext mongoMappingContext()
throws ClassNotFoundException {
// TODO Auto-generated method stub
return super.mongoMappingContext();
}
#Override
#Bean
public Mongo mongo() throws Exception {
return new MongoClient(mongoHost + ":" + mongoPort);
}
#Override
protected String getDatabaseName() {
// TODO Auto-generated method stub
return mongoDB;
}
}
In case that somebody is trying to connect to a Atlas MongoDB Cluster in application.properties has to have a config like:
spring.data.mongodb.uri=mongodb+srv://databaseUsername:usernamePassword#cluster0.j4koa.mongodb.net/databaseUsername?retryWrites=true&w=majority
In my case I needed to set up MongoDB for integration tests using Testcontainers. Using properites file was not an option since Mongo port had to be specified during runtime. I wanted to preseve original MongoDB autoconfiguration provided by SpringBoot but override some of the properties. This can be achieved by defining a bean of type MongoClientSettingsBuilderCustomizer which can be used to customize mongo settings :
#Bean
public MongoClientSettingsBuilderCustomizer clientSettingsBuilderCustomizer(final GenericContainer<?> mongoDBContainer) {
String database = environment.getProperty("spring.data.mongodb.database");
ConnectionString connectionString = new ConnectionString(String.format("mongodb://localhost:%s/%s", mongoDBContainer.getFirstMappedPort(), database));
return settings -> settings.applyConnectionString(connectionString);
}
If you simply want to read a MongoDB connection string from an environment variable, one way is to set the following environment variable:
SPRING_DATA_MONGODB_URI=mongodb://localhost:27017/trying-mongo
This doesn't require any changes in the application.properties as the spring data mongo will read the value from the above environment variable by default.
Here is How you can do in Spring Boot 2.0 by creating custom MongoClient adding Providing more control for Connection ,
Please follow github Link for Full Source Code
#Configuration
#EnableMongoRepositories(basePackages = { "com.frugalis.repository" })
#ComponentScan(basePackages = { "com.frugalis.*" })
#PropertySource("classpath:application.properties")
public class MongoJPAConfig extends AbstractMongoConfiguration {
#Value("${com.frugalis.mongo.database}")
private String database;
#Value("${com.frugalis.mongo.server}")
private String host;
#Value("${com.frugalis.mongo.port}")
private String port;
#Value("${com.frugalis.mongo.username}")
private String username;
#Value("${com.frugalis.mongo.password}")
private String password;
#Override
protected String getDatabaseName() {
return database;
}
#Override
protected String getMappingBasePackage() {
return "com.frugalis.entity.mongo";
}
#Bean
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongoClient(), getDatabaseName());
}
#Override
#Bean
public MongoClient mongoClient() {
List<MongoCredential> allCred = new ArrayList<MongoCredential>();
System.out.println("???????????????????"+username+" "+database+" "+password+" "+host+" "+port);
allCred.add(MongoCredential.createCredential(username, database, password.toCharArray()));
MongoClient client = new MongoClient((new ServerAddress(host, Integer.parseInt(port))), allCred);
client.setWriteConcern(WriteConcern.ACKNOWLEDGED);
return client;
}}