Redis - Lab 3
This lab will introduce an entity integration with Redis database with Java.
1. Create an entity
Steps
- Create a class called
User
in theexpert.os.labs.persistence
package - Annotate this class with
@Entity
, indicating that it's a persistent entity -
Add the following
private
fields with its typestype field String
userName
String
name
Map<String, String>
settings
Set<String>
languages
-
Annotate the
userName
with@Id
from thejakarta.nosql
package - Create a constructor using all fields
- Create get methods for each field
- Add the
toString()
method
Expected results
- Entity
User
created
Solution
Click to see...
import jakarta.nosql.Entity;
import jakarta.nosql.Id;
import java.util.Map;
import java.util.Set;
@Entity
public class User {
@Id
private String userName;
private String name;
private Map<String, String> settings;
private Set<String> languages;
public User() {
}
public User(String userName, String name, Map<String, String> settings, Set<String> languages) {
this.userName = userName;
this.name = name;
this.settings = settings;
this.languages = languages;
}
public String getUserName() {
return userName;
}
public String getName() {
return name;
}
public Map<String, String> getSettings() {
return settings;
}
public Set<String> getLanguages() {
return languages;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", name='" + name + '\'' +
", settings=" + settings +
", languages=" + languages +
'}';
}
}
2. Implement the Builder class
Steps
- Create a class called
UserBuilder
in theexpert.os.labs.persistence
package - Add the same fields we had previously added to the
User
class, without the annotations -
Add the builder methods for each field
-
example using the
userName
field
-
-
Add the
build()
method creating a new instance ofUser
using its constructor -
In the
User
class add the builder method referring to theUserBuilder
Expected results
- A new
UserBuilder
class implementing the Builder pattern for theUser
class - A new
builder()
method in theUser
class
Solution
Click to see...
import java.util.Collections;
import java.util.Map;
import java.util.Set;
public class UserBuilder {
private String username;
private String name;
private Map<String, String> settings = Collections.emptyMap();
private Set<String> languages = Collections.emptySet();
public UserBuilder username(String username) {
this.username = username;
return this;
}
public UserBuilder name(String name) {
this.name = name;
return this;
}
public UserBuilder settings(Map<String, String> settings) {
this.settings = settings;
return this;
}
public UserBuilder languages(Set<String> languages) {
this.languages = languages;
return this;
}
public User build() {
return new User(username, name, settings, languages);
}
}
3. Define the repository interface
- Create an
interface
calledUserRepository
in theexpert.os.labs.persistence
package - Annotate the class with
@Repository
from thejakarta.data.repository
package extends
the class usingCrudRepository<User, String>
from thejakarta.data.repository
package
Expected results
- The
UserRepository
that specifies methods for performing CRUD (Create, Read, Update, Delete) operations onUser
entities
Solution
Click to see...
4. Create the execution class
Steps
- Create a class called
AppUser
in theexpert.os.labs.persistence
package -
Add a main method
-
Set up a try-with-resources block, inside the
main
method, to manage the Jakarta EESeContainer
that is responsible for dependency injection and managing resources -
Obtain an instance of the
KeyValueTemplate
to interact with the key-value store -
Create two user instances using the builder from the
User
class with different data inside thetry
statementUser user1 = User.builder().username("user1").name("Otavio Santana") .languages(Set.of("Portuguese", "English", "Spanish", "Italian", "French")) .settings(Map.of("location", "Portugal", "currency", "EUR")).build(); User user2 = User.builder().username("user2").name("Poliana Santana") .languages(Set.of("Portuguese", "English")) .settings(Map.of("location", "Portugal", "currency", "EUR")).build();
-
Add the two user instances into the key-value store using the
KeuValueTemplate
, where the second one will have a delay of 1 second -
Retrieve the
user2
data based on itsuserName
and printout the result- use the method
get()
from thetemplate
field - the first parameter is the value of the
userName
field and the second parameter is the class
- use the method
-
Add a wait time, then retrieve and printout the same user again
-
Retrieve the
user1
data based on itsuserName
and printout the result -
Define a private constructor for the
AppUser
class to prevent instantiation since it contains only static methods: -
Run the
main()
method
Expected results
-
The following output
User2 data: Optional[User{userName='user2', name='Poliana Santana', settings={location=Portugal, currency=EUR}, languages=[English, Portuguese]}] User2 second retrieve data: Optional.empty User1 data: Optional[User{userName='user1', name='Otavio Santana', settings={location=Portugal, currency=EUR}, languages=[English, Italian, French, Portuguese, Spanish]}]
-
The second printout, related to the
user2
does not show any data because it expired
Solution
Click to see...
import jakarta.enterprise.inject.se.SeContainer;
import jakarta.enterprise.inject.se.SeContainerInitializer;
import jakarta.nosql.keyvalue.KeyValueTemplate;
import java.time.Duration;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
public class AppUser {
public static void main(String[] args) throws InterruptedException {
try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
KeyValueTemplate template = container.select(KeyValueTemplate.class).get();
User user1 = User.builder().username("user1").name("Otavio Santana")
.languages(Set.of("Portuguese", "English", "Spanish", "Italian", "French"))
.settings(Map.of("location", "Portugal", "currency", "EUR")).build();
User user2 = User.builder().username("user2").name("Poliana Santana")
.languages(Set.of("Portuguese", "English"))
.settings(Map.of("location", "Portugal", "currency", "EUR")).build();
template.put(user1);
template.put(user2, Duration.ofSeconds(1));
Optional<User> user2Data = template.get("user2", User.class);
System.out.println("User2 data: " + user2Data);
TimeUnit.SECONDS.sleep(2L);
Optional<User> user2DataSecondRetrieve = template.get("user2", User.class);
System.out.println("User2 second retrieve data: " + user2DataSecondRetrieve);
Optional<User> user1Data = template.get("user1", User.class);
System.out.println("User1 data: " + user1Data);
}
}
}
5. Use the UserRepository
with Redis
Steps
- Create an interface called
UserRepository
in theexpert.os.labs.persistence
package - Annotate the class with
@Repository
from thejakarta.data.repository
package -
Extends the interface using the
CrudRepository
Expected results
- The integration in Redis with the repository to perform the CRUD operations in the
User
entity
Solution
Click to see...
6. Using the UserRepository
Steps
- Create a class called
AppRepository
in theexpert.os.labs.persistence
package -
Add a main method
-
Set up a try-with-resources block, inside the
main
method, to manage the Jakarta EESeContainer
that is responsible for dependency injection and managing resources -
Add the
UserRepository
instance -
Create a new
User
object -
Save the
User
object -
Retrieve the
User
object saved by its id, which isusername
, using thefindById
method from the repository and printout the result -
Check if a user already exists using the
existsById
method from the repository, and printout the result -
Delete the user using the
deleteById
method -
Check if a user still exists using the
existsById
method from the repository, and printout the result -
Define a private constructor for the
AppRepository
class to prevent instantiation since it contains only static methods: -
Run the
main()
method
Expected results
-
The following output
Solution
Click to see...
import jakarta.enterprise.inject.se.SeContainer;
import jakarta.enterprise.inject.se.SeContainerInitializer;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
public class AppRepository {
public static void main(String[] args) {
try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
UserRepository repository = container.select(UserRepository.class).get();
User ada = User.builder().username("ada").name("Ada Lovelace")
.languages(Set.of("Latin")).settings(Map.of("currency", "food")).build();
repository.save(ada);
Optional<User> userFound = repository.findById("ada");
System.out.println(userFound);
boolea userExist = repository.existsById("ada");
System.out.println("userExist? = " + userExist);
repository.deleteById("ada");
userExist = repository.existsById("ada");
System.out.println("userExist? = " + userExist);
}
}
private AppRepository() {
}
}