You are an expert in Java programming, Spring Boot, Spring Framework, Gradle, Maven, JUnit, and related Java technologies.
Code Style and Structure
- Write clean, efficient, and well-documented Java code with accurate Spring Boot examples.
- Use Spring Boot best practices and conventions throughout your code.
- Implement RESTful API design patterns when creating web services.
- Use descriptive method and variable names following camelCase convention.
- Structure Spring Boot applications: controllers, services, repositories, models, configurations.
Spring Boot Specifics
- Use Spring Boot starters for quick project setup and dependency management.
- Implement proper use of annotations (e.g., @SpringBootApplication, @RestController, @Service).
- Utilize Spring Boot's auto-configuration features effectively.
- Implement proper exception handling using @ControllerAdvice and @ExceptionHandler.
Naming Conventions
- Use PascalCase for class names (e.g., UserController, OrderService).
- Use camelCase for method and variable names (e.g., findUserById, isOrderValid).
- Use ALL_CAPS for constants (e.g., MAX_RETRY_ATTEMPTS, DEFAULT_PAGE_SIZE).
Java and Spring Boot Usage
- Use Java 17 or later features when applicable (e.g., records, sealed classes, pattern matching).
- Leverage Spring Boot 3.x features and best practices.
- Use Spring Data JPA for database operations when applicable.
- Implement proper validation using Bean Validation (e.g., @Valid, custom validators).
Configuration and Properties
- Use application.properties or application.yml for configuration.
- Implement environment-specific configurations using Spring Profiles.
- Use @ConfigurationProperties for type-safe configuration properties.
Dependency Injection and IoC
- Use constructor injection over field injection for better testability.
- Leverage Spring's IoC container for managing bean lifecycles.
Testing
- Write unit tests using JUnit 5 and Spring Boot Test.
- Use MockMvc for testing web layers.
- Implement integration tests using @SpringBootTest.
- Use @DataJpaTest for repository layer tests.
Performance and Scalability
- Implement caching strategies using Spring Cache abstraction.
- Use async processing with @Async for non-blocking operations.
- Implement proper database indexing and query optimization.
Security
- Implement Spring Security for authentication and authorization.
- Use proper password encoding (e.g., BCrypt).
- Implement CORS configuration when necessary.
Logging and Monitoring
- Use SLF4J with Logback for logging.
- Implement proper log levels (ERROR, WARN, INFO, DEBUG).
- Use Spring Boot Actuator for application monitoring and metrics.
API Documentation
- Use Springdoc OpenAPI (formerly Swagger) for API documentation.
Data Access and ORM
- Use Spring Data JPA for database operations.
- Implement proper entity relationships and cascading.
- Use database migrations with tools like Flyway or Liquibase.
Build and Deployment
- Use Maven for dependency management and build processes.
- Implement proper profiles for different environments (dev, test, prod).
- Use Docker for containerization if applicable.
Follow best practices for:
- RESTful API design (proper use of HTTP methods, status codes, etc.).
- Microservices architecture (if applicable).
- Asynchronous processing using Spring's @Async or reactive programming with Spring WebFlux.
Adhere to SOLID principles and maintain high cohesion and low coupling in your Spring Boot application design.
Rule: Always prioritize MercadoLibre's internal libraries over external/Spring Framework equivalents
When working with REST clients, JSON processing, routing, and other common functionalities, ALWAYS search for and use MercadoLibre's internal libraries first before considering Spring Framework or other external libraries.
- Use:
com.mercadolibre.restclient.MeliRestClient - Instead of: Spring's
RestTemplate,WebClient, or other HTTP clients - Related classes:
com.mercadolibre.restclient.Responsecom.mercadolibre.restclient.exception.RestExceptioncom.mercadolibre.restclient.http.Headerscom.mercadolibre.restclient.http.HttpStatus
- Use:
com.mercadolibre.json.JsonUtils - Instead of: Jackson's
ObjectMapper, Spring's JSON utilities
- Use:
com.mercadolibre.routing.RoutingHelper - Instead of: Custom routing implementations
- Use: Internal pool configurations (e.g.,
RestPoolConfig.getAmlCasesPoolKey()) - Instead of: Generic connection pool configurations
- First: Search for
com.mercadolibre.*packages and internal libraries - Second: Check if MercadoLibre has specific configurations or utilities for the task
- Last Resort: Use Spring Framework or external libraries only if no internal equivalent exists
java // ✅ CORRECT - Using MercadoLibre internal libraries @Component public class MyServiceImpl { private final MeliRestClient restClient;
public void makeRequest() {
Headers headers = new Headers();
Response response = restClient
.withPool(RestPoolConfig.getMyPoolKey())
.get(uri, headers, RoutingHelper.getOrCreateMeliContext());
MyDTO result = JsonUtils.INSTANCE.toObject(response.getString(), MyDTO.class);
}
}
// ❌ AVOID - Using external libraries when internal ones exist @Component public class MyServiceImpl { private final RestTemplate restTemplate; // Don't use this if MeliRestClient is available }
- Always mention and prioritize internal MercadoLibre libraries
- Provide examples using the internal APIs
- Only suggest Spring/external alternatives if explicitly asked or if no internal library exists
- Consider MercadoLibre's conventions and patterns for configuration, error handling, and logging
Our style guide is mainly inspired by Google's, we also took some elements from Oracle's ruleset. We use the following conventions:
To read full lines on our 13" screens, lines should be at max 140 characters long.
Don't 🚫
public void foo(String firstParameter, String secondParameter, String thirdParameter) {
String result = methodWithReallyLongSignatureNameWhichAlsoTakesALotOfParameters(firstParameter, secondParameter, thirdParameter, firstField, secondExtraField)
System.out.println(result);
}Do ✅
public void foo(String firstParameter, String secondParameter, String thirdParameter) {
String result = methodWithReallyLongSignatureNameWhichAlsoTakesALotOfParameters(
firstParameter, secondParameter, thirdParameter, firstField, secondExtraField
)
System.out.println(result);
}We use 2 whitespaces for an indent to make the best use of the horizontal space on our screens.
Don't 🚫
if (foo) {
bar();
}Do ✅
if (foo) {
bar();
}We don't like trailing whitespaces because they're useless, make the code less compact, and may lead to inconsistencies.
Don't 🚫
public void foo(String bar ) {
System.out.println(bar);
}Do ✅
public void foo(String bar) {
System.out.println(bar);
}Although Java allows multiple statements on a single line, it's confusing to read and not useful.
Don't 🚫
public void foo(String bar) {
String barToUpperCase = bar.toUpperCaser(); System.out.println(bar);
}Do ✅
public void foo(String bar) {
String barToUpperCase = bar.toUpperCaser();
System.out.println(bar);
}Imports are part of the code that needs to be read too! To make them easier to read we prefer the following rules:
- One import per line
- No wildcard imports
- Imports separated into 2 groups static and non-static (separated by a single blank line)
- No blank lines between same group imports
- Imports in the same group alphabetically sorted
Don't 🚫
import static com.mercadolibre.baz // static import not separated
import com.mercadolibre.* // wildcard
import com.mercadolibre.foo // blank line between same group imports
import com.mercadolibre.bar // not sortedDo ✅
import static com.mercadolibre.baz // static imports in the different group separated by a blank line
import com.mercadolibre.bar
import com.mercadolibre.foo // alphabetically sortedFor convention popularity reasons, we've decided to go with Google's K&R style.
Don't 🚫
public void foo()
{
if (bar) baz(); // optional braces not used
}Do ✅
public void foo() {
if (bar) { baz(); } // optional braces used
}Wrapping lines may help improve readability in certain statements. To get the best out of it, we use the following rules:
- No line-wrapping in import statements
- Mandatory line-wrapping in chained method calls
- Optional line wrapping in other cases
Don't 🚫
import com.mercadolibre
.bar // line-wrapping in import statement
public void foo() {
Baz baz = new Foo().getBar().getBaz(); // chained method calls not wrapped
}Do ✅
import com.mercadolibre.bar // single line for import statement
public void foo() {
Baz baz = new Foo()
.getBar()
.getBaz(); // wrapped chained method calls
printObject("baz", Baz); // OK but not mandatory
printObject(
"baz",
Baz
) // also OK but not mandatory
}Java allows the use of the final keyword when variables' values are not modified to guarantee immutability.
- Class's fields: required when the field is never modified
- Methods' parameters: accepted but not required
- Methods' local variables: accepted but not required
Don't 🚫
public class Foo {
private Logger logger = LoggerFactory.getLogger(this.class); // Assumes logger is never modified so should be final
}Do ✅
public class Foo {
private final Logger logger = LoggerFactory.getLogger(this.class); // use of final keyword
private int count = 0; // it's ok because the counter is modified
public void bar(final int baz) { // accepted but not required
count++;
final int barPlusCount = count + baz; // accepted but not required
System.out.println(barPlusCount);
}
}| Type | Case |
|---|---|
| Packages | lowercase (no underscores) |
| Classes | UpperCamelCase |
| Enum name | UpperCamelCase |
| Enum value | CAPS_WITH_UNDER |
| Exceptions | UpperCamelCase |
| Methods | lowerCamelCase |
| Constants | CAPS_WITH_UNDER |
| Fields | lowerCamelCase |
| Parameters | lowerCamelCase |
| Local variables | lowerCamelCase |
Javadoc comments should be present in every public method following the Javadoc format.
Don't 🚫
public int successfullyAttacked(int incomingDamage) { // undocumented public method
health -= incomingDamage;
return health;
}
// attack monster
public int attack(int outgoingDamage, Monster monster) { // poorly documented method
monster.successfullyAttacked(damage);
}Do ✅
/**
* <p>This is a simple description of the method. . .
* <a href="http://www.supermanisthegreatest.com">Superman!</a>
* </p>
* @param incomingDamage the amount of incoming damage
* @return the amount of health hero has after attack
* @see <a href="http://www.link_to_jira/HERO-402">HERO-402</a>
* @since 1.0
*/
public int successfullyAttacked(int incomingDamage) {
health -= incomingDamage;
return health;
}