Propify is a powerful, lightweight Java annotation processor that eliminates configuration errors by generating type-safe classes from your configuration files (YAML, INI, or .properties
) and internationalization bundles.
Say goodbye to "stringly-typed" keys and runtime errors! Access every configuration value and message through strongly-typed Java methods, catching invalid accesses at compile time instead of runtime.
Propify seamlessly supports nested properties, custom lookup providers, and full ICU4J formatting while adding zero runtime dependencies to your application.
- Why Propify?
- Features
- Requirements
- Installation
- Quick Start
- Advanced Usage
- Internationalization (i18n)
- How It Works
- Examples
- Getting Help
- Contributing
- License
- Acknowledgments
- Type-Safety: Access configuration and messages via Java methods—no more stringly-typed keys.
- Compile-Time Guarantees: Prevent typos in code (incorrect keys) from compiling, so invalid property accesses are caught before runtime.
- Productivity: Skip manual parsing and error-prone lookups.
- Extendable: Plug in custom lookup providers for environment variables, system properties, or your own sources.
- 🔒 Type-Safe Config: Generates POJOs from YAML, INI, or
.properties
files - 🌐 Type-Safe i18n: Strongly-typed resource bundles with ICU4J formatting
- 🛠 Compile-Time Validation: Syntax and schema checks during build
- 📚 Nested Keys: Dot-notation support for hierarchical configs
- 🔄 Custom Lookups: Inject dynamic values (env, system props, custom)
- ⚡️ Zero Runtime Overhead: All code generated at compile time
- Java: 8 or higher
- Build: Maven or Gradle
Add dependency and annotation processor:
<dependencies>
<dependency>
<groupId>com.vgerbot</groupId>
<artifactId>propify</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>com.vgerbot</groupId>
<artifactId>propify</artifactId>
<version>2.0.0</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
dependencies {
implementation 'com.vgerbot:propify:2.0.0'
annotationProcessor 'com.vgerbot:propify:2.0.0'
}
plugins {
id 'net.ltgt.apt' version '0.21'
}
dependencies {
compile 'com.vgerbot:propify:2.0.0'
apt 'com.vgerbot:propify:2.0.0'
}
For other tools, configure your build to include
propify
as an annotation processor.
-
Create
src/main/resources/application.yml
:server: host: localhost port: 8080 database: url: jdbc:mysql://localhost:3306/mydb username: root password: secret
-
Annotate an interface:
@Propify(location = "application.yml") public interface AppConfig {}
-
Use the generated API:
public class Main { public static void main(String[] args) { AppConfigPropify cfg = new AppConfigPropify(); System.out.println(cfg.getServer().getHost()); System.out.println(cfg.getDatabase().getUrl()); } }
Configuration locations can be:
- On the classpath (e.g.,
application.yml
insrc/main/resources/
) - Local file system (
file:///path/to/config.yml
) - HTTP/HTTPS URL (
https://...
)
For example:
@Propify(location = "https://example.com/config.yml")
public interface WebConfig {}
⚠️ Ensure your configuration files are reachable at build time—whether via classpath, file path, or network URL.
@Propify(
location = "application.yml",
generatedClassName = "CustomConfigImpl"
)
public interface AppConfig {}
By default, Propify infers file format from the file extension (.yml
/.yaml
for YAML, .ini
for INI, .properties
for Java properties). Manual mediaType
specification is only required when the extension is non-standard or ambiguous.
@Propify(
location = "config.custom", // non-standard extension
mediaType = "application/x-java-properties"
)
public interface AppConfig {}
Propify lets you interpolate dynamic values at build time via lookup providers. Out of the box you can use placeholders in your config:
- Environment variables:
{env:VAR_NAME}
- Custom lookups:
{lookupName:variableName}
— resolved by the corresponding lookup class
Example configuration (application.yml
):
app:
tempDir: "{env:TEMP_DIR}"
secretKey: "{vault:db-secret}"
Annotate your interface:
@Propify(
location = "application.yml",
lookups = {
CustomEnvironmentLookup.class, // resolves {env:...}
VaultLookup.class // resolves {vault:...}
}
)
public interface AppConfig {}
Usage in code:
AppConfig cfg = new AppConfigPropify();
String tempDir = cfg.getApp().getTempDir(); // from $TEMP_DIR
String secret = cfg.getApp().getSecretKey(); // from vault lookup
Generate type-safe resource bundles using ICU4J:
-
Create message files in
resources/
:# messages.properties (default) welcome=Welcome greeting=Hello, {name}! # messages_zh_CN.properties welcome=欢迎 greeting=你好, {name}!
-
Annotate a class:
@I18n(baseName = "messages", defaultLocale = "en") public class Messages {}
-
Access messages:
String hi = MessageResource.getDefault().greeting("Alice"); String hiZh = MessageResource.get(Locale.CHINESE).greeting("张三");
Supports pluralization, dates, numbers, and custom ICU patterns—fully validated at compile time.
- Scan for
@Propify
and@I18n
annotations - Parse configuration and message files
- Generate Java implementation classes
- Compile everything together—fail-fast on errors
Here are some practical examples of how to use Propify in common scenarios:
// application.yml
// server:
// http:
// port: 8080
// https:
// port: 8443
// keystore: /path/to/keystore
@Propify(location = "application.yml")
public interface ServerConfig {}
// Usage
ServerConfigPropify config = new ServerConfigPropify();
int httpPort = config.getServer().getHttp().getPort(); // 8080
String keystore = config.getServer().getHttps().getKeystore(); // /path/to/keystore
// Using environment variables in your config
// app.yml
// database:
// url: "jdbc:mysql://{env:DB_HOST}:{env:DB_PORT}/{env:DB_NAME}"
@Propify(
location = "app.yml",
lookups = { EnvironmentLookup.class }
)
public interface AppConfig {}
If you encounter any issues or have questions about using Propify:
- GitHub Issues: Submit a new issue on our GitHub repository
- Documentation: Check the Wiki for detailed documentation
- Examples: Browse the examples directory for sample projects
- Fork the repo
- Create a feature branch (
git checkout -b feature/xyz
) - Implement and test your changes
- Submit a Pull Request
Please follow the existing coding style and update tests.
MIT © 2024 vgerbot-libraries
- JavaPoet - Java source file generation
- Jackson YAML - YAML parsing
- Apache Commons Configuration - Configuration management
- ICU4J - Internationalization support