Learn through practical examples and real-world implementation patterns.
Get started with MetaObjects in your Java project. Add the dependency and create your first metadata definition.
<dependency>
<groupId>com.metaobjects</groupId>
<artifactId>metaobjects-core</artifactId>
<version>6.2.5-SNAPSHOT</version>
</dependency>
implementation 'com.metaobjects:metaobjects-core:6.2.5-SNAPSHOT'
Define a simple object structure using MetaObjects JSON metadata format.
{
"metadata": {
"name": "user-objects",
"version": "1.0",
"children": [
{
"object": {
"name": "User",
"type": "pojo",
"description": "User entity with validation",
"children": [
{
"field": {
"name": "id",
"type": "long",
"@required": true,
"@primaryKey": true
}
},
{
"field": {
"name": "username",
"type": "string",
"@required": true,
"@minLength": 3,
"@maxLength": 50,
"@pattern": "^[a-zA-Z0-9_]+$"
}
},
{
"field": {
"name": "email",
"type": "string",
"@required": true,
"@pattern": "^[\\w._%+-]+@[\\w.-]+\\.[A-Za-z]{2,}$"
}
},
{
"field": {
"name": "createdAt",
"type": "datetime",
"@required": true,
"@default": "NOW()"
}
}
]
}
}
]
}
}
Load your metadata and start using it in your Java application.
// Initialize MetaObjects registry
MetaDataRegistry registry = new MetaDataRegistry();
// Load metadata from JSON file
registry.loadFromFile("user-objects.json");
// Get object metadata
MetaData userMetadata = registry.getMetaData("User");
// Access field information
Field usernameField = userMetadata.getField("username");
String pattern = usernameField.getAttribute("pattern");
Integer maxLength = usernameField.getAttribute("maxLength");
// Validate data
ValidationResult result = userMetadata.validate(userData);
if (!result.isValid()) {
result.getErrors().forEach(System.out::println);
}
Integrate MetaObjects with Spring Boot for automatic configuration and dependency injection.
@Configuration
@EnableMetaObjects
public class MetaObjectsConfig {
@Bean
public MetaDataRegistry metaDataRegistry() {
MetaDataRegistry registry = new MetaDataRegistry();
registry.loadFromClasspath("metadata/");
return registry;
}
@Bean
public MetaObjectValidator validator(MetaDataRegistry registry) {
return new MetaObjectValidator(registry);
}
}
@Service
public class UserService {
@Autowired
private MetaDataRegistry registry;
@Autowired
private MetaObjectValidator validator;
public User createUser(UserRequest request) {
// Get metadata for validation
MetaData userMetadata = registry.getMetaData("User");
// Validate input
ValidationResult result = validator.validate(request, userMetadata);
if (!result.isValid()) {
throw new ValidationException(result.getErrors());
}
// Create and save user
User user = new User();
user.setUsername(request.getUsername());
user.setEmail(request.getEmail());
user.setCreatedAt(Instant.now());
return userRepository.save(user);
}
}
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public ResponseEntity<User> createUser(@RequestBody UserRequest request) {
try {
User user = userService.createUser(request);
return ResponseEntity.ok(user);
} catch (ValidationException e) {
return ResponseEntity.badRequest()
.body(new ErrorResponse(e.getErrors()));
}
}
}
Generate consistent code across multiple languages from your metadata definitions.
// Generated Java POJO
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 50)
@Pattern(regexp = "^[a-zA-Z0-9_]+$")
@Size(min = 3, max = 50)
private String username;
@Column(nullable = false)
@Email
private String email;
@Column(nullable = false)
@CreationTimestamp
private Instant createdAt;
// Generated getters, setters, equals, hashCode, toString
}
// Generated TypeScript interface and validation
export interface User {
id: number;
username: string;
email: string;
createdAt: string;
}
export class UserValidator {
static validate(user: Partial<User>): ValidationResult {
const errors: string[] = [];
if (!user.username || user.username.length < 3 || user.username.length > 50) {
errors.push("Username must be 3-50 characters");
}
if (!/^[a-zA-Z0-9_]+$/.test(user.username || '')) {
errors.push("Username contains invalid characters");
}
if (!user.email || !/^[\w._%+-]+@[\w.-]+\.[A-Za-z]{2,}$/.test(user.email)) {
errors.push("Invalid email format");
}
return { valid: errors.length === 0, errors };
}
}
-- Generated SQL DDL
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
email VARCHAR(255) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT uk_users_username UNIQUE (username),
CONSTRAINT uk_users_email UNIQUE (email),
CONSTRAINT ck_users_username CHECK (username REGEXP '^[a-zA-Z0-9_]+$'),
CONSTRAINT ck_users_email CHECK (email REGEXP '^[\\w._%+-]+@[\\w.-]+\\.[A-Za-z]{2,}$')
);
-- Generated indexes
CREATE INDEX idx_users_created_at ON users(created_at);
CREATE INDEX idx_users_email ON users(email);
Pharmaceutical company uses MetaObjects for clinical trial data structures that need to adapt to changing regulatory requirements.
Learning management system adapts course structures and assessment criteria without redeployment.
Trading platform handles complex financial instruments with varying data structures and validation rules.
Create custom field types with specialized validation and behavior.
public class CurrencyField extends PrimitiveField<BigDecimal> {
public static void registerTypes(MetaDataRegistry registry) {
registry.registerType(CurrencyField.class, def -> def
.type("field").subType("currency")
.inheritsFrom("field", "base")
.optionalAttribute("precision", "int")
.optionalAttribute("currencyCode", "string")
.optionalAttribute("minValue", "decimal")
.optionalAttribute("maxValue", "decimal")
);
}
@Override
public ValidationResult validate(BigDecimal value) {
ValidationResult result = super.validate(value);
if (value != null) {
// Check precision
Integer precision = getAttribute("precision");
if (precision != null && value.scale() > precision) {
result.addError("Value exceeds allowed precision of " + precision);
}
// Check range
BigDecimal minValue = getAttribute("minValue");
BigDecimal maxValue = getAttribute("maxValue");
if (minValue != null && value.compareTo(minValue) < 0) {
result.addError("Value below minimum: " + minValue);
}
if (maxValue != null && value.compareTo(maxValue) > 0) {
result.addError("Value above maximum: " + maxValue);
}
}
return result;
}
}
Handle schema changes at runtime without downtime.
@Component
public class SchemaEvolutionService {
@Autowired
private MetaDataRegistry registry;
@Autowired
private ApplicationEventPublisher eventPublisher;
public void evolveSchema(String objectName, SchemaChange change) {
MetaData metadata = registry.getMetaData(objectName);
MetaData newMetadata = applyChange(metadata, change);
// Validate the change
ValidationResult validation = validateSchemaChange(metadata, newMetadata);
if (!validation.isValid()) {
throw new SchemaEvolutionException(validation.getErrors());
}
// Apply change atomically
registry.updateMetaData(newMetadata);
// Notify listeners
eventPublisher.publishEvent(new SchemaChangedEvent(objectName, change));
log.info("Schema evolved for {}: {}", objectName, change.getDescription());
}
private ValidationResult validateSchemaChange(MetaData old, MetaData updated) {
SchemaCompatibilityChecker checker = new SchemaCompatibilityChecker();
return checker.checkCompatibility(old, updated);
}
}
Ready to implement these patterns in your project? Get started with our comprehensive documentation.