It uses Java annotation processor for mapping a ResultSet to the object's fields at compile time. There's no runtime performance overhead like in some libraries, that need to use reflection to find out the fields' names and types.
You can always check the generated code. Please, open an issue if you think the generated code could be improved.
https://github.com/tivrfoa/MapResultSet/tree/main/generatedSources/org/acme/dao
The two required annotations for using MapResultSet are Table
and Query
.
The @Column
annotation is required if the column name is different from the field name.
There are also the following annotations to map relationships:
- Id (necessary to group the relationships)
- OneToOne
- OneToMany
- ManyToOne
- ManyToMany
The variable annotated with @Query
must be final, eg:
@Query
final String listPeople;
And due to Java Annotation Processor limitation, the queries must not be local variables.
MapResultSet has some restrictions regarding your queries. These restrictions could be handled, but I think they make your query more readable too. xD
- Join must be done using JOIN, not in WHERE clause;
- Values returned from SELECT that are not a simple column name must
have an alias and be preceded with
AS
, eg: select 1 as one; select age + 18 as something; - Columns in
select
must be preceded by the table name (or alias) if thefrom
clause contains more than one table; - Table alias must be preceded by
AS
Please, open an issue if you have a query that meets these requirements, but fails to work.
Generated classes will be in the same package that contains the @Query
.
There will be one MapResultSet class created per package that contains a @Query
.
Each @Query
also creates a class with the name of the query with the first letter in uppercase,
followed by Records, eg: the query below will create a class called ListPeopleRecords.
@Query
final String listPeople;
ps: if the query contains only one table and there's no temporary columns, then this class is not created and MapResultSet returns a list of the only class in the query.
By default MapResultSet assumes you are using a List
and it creates it with ArrayList
,
but you can use any collection you want, as long as you tell which method to use to create
the collection, and which method should be used to add elements to it.
The create methods must be static
and not accept any parameters.
Example using HashSet and LinkedList:
@Table (name = "country")
public record Country(@Id int id, float density, String name,
double squareMeters, @Column (name = "phone_code") int phoneCode,
long someBigNumber, BigInteger evenBigger,
// It doesn't make sense for Country to have a list of Person ...
// It's just for testing.
@OneToMany (createWith = "newHashSet()", addWith = "add") Set<Person> listPerson,
// Just for tests. This is actually a OneToMany
@ManyToMany (createWith = "newLinkedList()", addWith = "add") List<State> states) {
public static List<State> newLinkedList() {
return new LinkedList<State>();
}
public static Set<Person> newHashSet() {
return new HashSet<Person>();
}
}
Add these to dependencies
:
<dependency>
<groupId>io.github.tivrfoa</groupId>
<artifactId>mapresultset</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>io.github.tivrfoa</groupId>
<artifactId>mapresultset-processor</artifactId>
<version>0.1.0</version>
</dependency>
And these to plugins
:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<executions>
<execution>
<id>process-annotations</id>
<phase>generate-sources</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<failOnError>false</failOnError>
<compilerArgs>
<arg>-proc:only</arg>
<arg>-implicit:none</arg>
<arg>-processor</arg>
<arg>io.github.tivrfoa.mapresultset.MappingProcessor</arg>
</compilerArgs>
</configuration>
</execution>
<execution>
<id>default-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<compilerArgs>
<arg>-proc:none</arg>
</compilerArgs>
</configuration>
</execution>
</executions>
</plugin>
Every time you use one of the MapResultSet annotations, you should run mvn clean compile
in order for the changes to become available for you.
Then you can just call MapResultSet.queryName(resultSet)
, eg:
@Query
private static final String listBooksOnly = """
select b.author_name, b.name
from book as b
order by b.author_name
""";
public static List<Book> listBooksOnly() {
try {
ResultSet resultSet = executeQuery(listBooksOnly);
return MapResultSet.listBooksOnly(resultSet);
} catch (SQLException ex) {
// ...
}
}