pogul
pogul

Reputation: 458

Maven: read properties from file if it exists and set default properties otherwise

I know that in many cases, it is (clunky but) possible to use two profiles to result in properties being read from a file if present and to set default values otherwise, e.g.

<profile>
    <id>my-default-props</id>
    <activation>
        <file>
            <missing>${my.file.path}</missing>
        </file>
    </activation>
    <properties>
        <my.prop1>Blah</my.prop1>
        <my.prop2>Another</my.prop2>
    </properties>
</profile>

<profile>
    <id>read-my-props</id>
    <activation>
        <file>
            <exists>${my.file.path}</exists>
        </file>
    </activation>
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>properties-maven-plugin</artifactId>
                <version>1.0-alpha-2</version>
                <executions>
                    <execution>
                        <phase>initialize</phase>
                        <goals>
                            <goal>read-project-properties</goal>
                        </goals>
                        <configuration>
                            <files>
                                <file>${my.file.path}</file>
                            </files>
                            <quiet>false</quiet>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</profile>

Unfortunately, this doesn't work for me: I need to override the value of "my.file.path" in various child projects, but profile activation is evaluated very early in the lifecycle. This means that the child project's value is not used during evaluation and the properties are never read properly.

It seems like a common enough requirement to me, but Googling is telling me otherwise. Can anyone please tell me how I can achieve this goal? Thanks.

Upvotes: 1

Views: 2787

Answers (1)

pogul
pogul

Reputation: 458

To answer my own question... I've found that rather than using a profile I can use a combination of two plugins with executions that fire one after the other in the same phase:

  1. properties-maven-plugin:read-project-properties with quiet set to true
  2. maven-antrun-plugin:run with <exportAntProperties>true</exportAntProperties>

Since the properties are only set if they do not already exist, this has the effect of setting default values.

Caveat: this isn't quite the same as setting a bunch of property defaults if the file does not exist. This is done on a per-property basis instead. This could potentially result in a mix of incoherent properties (e.g. MySQL database driver with a PostgreSQL database URL).

Example:

       <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>properties-maven-plugin</artifactId>
        <version>1.0-alpha-2</version>
        <executions>
            <execution>
                <id>read-my-properties</id>
                <phase>initialize</phase>
                <goals>
                    <goal>read-project-properties</goal>
                </goals>
                <configuration>
                    <files>
                        <file>${my.properties.file}</file>
                    </files>
                    <quiet>true</quiet>
                </configuration>
            </execution>
        </executions>
    </plugin>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <executions>
            <execution>
                <id>set-default-properties</id>
                <phase>initialize</phase>
                <goals>
                    <goal>run</goal>
                </goals>
                <configuration>
                    <exportAntProperties>true</exportAntProperties>
                    <target>
                        <property name="db.driver" value="org.postgresql.Driver"/>
                        <property name="db.name" value="my_db_name"/>
                        <!-- etc. -->
                    </target>
                </configuration>
            </execution>
        </executions>
    </plugin>

The key thing here is that there is no profile activation evaluation happening - which wouldn't work as it is happens too early. The ${my.properties.file} property can safely be used during the <execution> blocks as these happen after the child project has had the opportunity to correctly override the value.

Upvotes: 3

Related Questions