Passing an entity into private methods for updating from request DTO - java

My Spring Boot application implements a Service class which is passed a request object from a RestController. This service method is responsible for updating an entity.
As there are a lot of fields to be updated, I separated the updating logic into several private methods for better readability like this:
#Transactional
public void updateUser(UserRequest userRequest) {}
final User user = userRepository.findById(userRequest.getId).orElseThrow(() -> new EntityNotFoundException()));
updateUserFromRequest(user, userRequest);
}
private void updateUserFromRequest(User user, UserRequest userRequest) {
updateUserMainData(user, userRequest);
updateUserAdditionalData(user, userRequest);
}
private void updateUserMainData(User user, UserRequest userRequest) {
user.setProperty1(userRequest.getProperty1());
user.setProperty2(userRequest.getProperty2());
user.setProperty3(userRequest.getProperty3());
}
private void updateUserAdditionalData(User user, UserRequest userRequest) {
user.setProperty4(userRequest.getProperty4());
user.setProperty5(userRequest.getProperty5());
user.setProperty6(userRequest.getProperty6());
}
While this works just fine, it feels "awkward" to pass around the User object into private methods. Is this apporach considered "good practice" or are there any other patterns?

One possibility could be hiding this complexity in the User class itself by adding an update(UserRequest userRequest) method. No more User being passed around into private methods (which could be considerer to have side effects).
If you don't want to add logic to your entity class, another possibility to make it less "awkward" would be to have all the updateXXXX() methods returning the updated User. Of course, this changes nothing in practical terms but it hints that the User was indeed updated in the method, reducing a little bit the "methods with side-effect" feeling.

Related

Update/notify other User in Spring Web

I have some design/implementation issue that I just can't wrap my head around it. I am currently working on a text-based game with multiple players. I kind of understand how it works for Player-to-Server, I meant that Server sees every individual Player as the same.
I'm using spring-boot 2, spring-web, thymeleaf, hibernate.
I implemented a custom UserDetails that returns after the user login.
#Entity
#Table(name = "USER")
public class User implements Serializable {
#Id
private long userId;
#Column(unique = true, nullable = false)
private String userName;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "playerStatsId")
private PlayerStats stats;
}
public class CurrentUserDetailsService implements UserDetailsService {
#Override
public CurrentUser loadUserByUsername(String userName) {
User user = this.accountRepository.findByUserName(userName)
.orElseThrow(() ->
new UsernameNotFoundException("User details not found with the provided username: " + userName));
return new CurrentUser(user);
}
}
public class CurrentUser implements UserDetails {
private static final long serialVersionUID = 1L;
private User user = new User();
public CurrentUser(User user) {
this.user = user;
}
public PlayerStats getPlayerStats() {
return this.user.getStats();
}
// removed the rest for brevity
}
Hence, in my controller, I can do this to get the CurrentUser.
*Note each User is also a player.
#GetMapping("/attackpage")
public String viewAttackPage(#AuthenticationPrincipal CurrentUser currentUser) {
// return the page view for list of attacks
return "someview";
}
The currentUser here would reflect to the current user per say (Player 1 or 2 or 3 and so on). Which works fine for most of the stuff happening to themselves such as purchasing some stuff, updating profile and so on.
But what I can't get or know how to achieve is when 2 players interact.
For example, Player 1 attacks Player 2. If I am Player 1, what I'll do is to click the "Attack" on the View and select the Player 2, and submit the command. Hence, in the controller, it will be something like this.
#GetMapping("/attack")
public String launchAttack(#AuthenticationPrincipal CurrentUser currentUser, #RequestParam("playername") String player2) {
updatePlayerState(player2);
return "someview";
}
public void updatePlayerState(String player) {
User user = getUserByPlayername(player);
// perform some update to player state (say health, etc)
// update back to db?
}
Here's is what really got me confused.
As seen previously, when each User/Player logs in, a set of user (player) current state will be pulled from the DB and store "in-memory".
Hence, when Player 1 attacks Player 2,
How do I "notify" or update Player 2 that the stats has changed, and thus, Player 2 should pull updated stats from db to memory.
How to tackle the possible concurrency issue here? For example, Player 2 health is 50 in DB. Player 2 then perform some action (say purchase health potion + 30), which then update the DB (health to 80). However, just before the DB is updated, Player 1 has already launch the attack and grab from DB the state of Player 2 where it will return 50 since DB has yet to be updated. So now, whatever changes made in getUserByPlayername() and update to the DB will be wrong, and the entire state of the Player will be "de-sync". I hope I am making sense here.
I understand that there is #Version in hibernate for optimistic locking but I'm not sure if it's applicable in this case. And would spring-session be useful in such case?
Should I not store the any data in memory when user login? Should I always be retrieving data from DB only when some action is performed? Like when viewProfile, then I pull from accountRepository. or when viewStats then I pull from statsRepository and on so.
Do point me in the right direction. Would appreciate for any concrete example of sort, or some kind of video/articles. If there is any additional information required, do let me know and I'll try to explain my case better.
Thank you.
I think that you should not be updating the currentUser in your Controller methods, and should not be relying on the data in that object to represent a player's current state. There are probably ways to get that to work, but you'd need to mess around with updating the security context.
I also recommend that you lookup Users by id instead of userName, so will write the rest of this answer with that approach. If you insist on finding Users by userName, adjust where necessary.
So, keeping it simple, I would have a reference to the accountRepository in the Controller, and then, whenever you need to get or update a player's state, use
User user = accountRepository.findById(currentUser.getId())
Yes, #Version and optimistic locking will help with the concurrency issues that you're concerned about. You can reload the Entity from the database, and retry the operation if you catch an #OptimisticLockException. Or, you may want to respond to player 1 with something like "Player 2 has just purchased a potion of healing, and is now 80 heath, do you still want to attack?"
I'm not a spring user, but I think that the problem is more conceptual than technical.
I'll try to provide an answer which uses a general approach, while writing the examples in a JavaEE style so that they should be understandable, and hopefully, portable to spring.
First of all: every single DETACHED entity is stale data. And stale data is not "trustable".
So:
each method that modify the state of an object should re-fetch the object from DB inside the transaction:
updatePlayerState() should be a transaction-boundary method (or called inside a tx), and getUserByPlayername(player) should fetch the target object from the DB.
JPA speaking: em.merge() is forbidden (without proper locking, i.e. #Version).
if you (or spring) are doing this already, there's little to add.
WRT the "lost update problem" you mention in your 2. be aware that this covers the application server side (JPA/Hibernate), but the very same problem could be present on DB side, which should be properly configured for, at least, repeatable read isolation. Take a look at MySQL does not conform to Repeatable Read really, if you are using it.
you have to handle controller fields that refer stale Players/Users/Objects. You have, at least, two options.
re-fetch for each request: suppose Player1 has attacked Player2 and diminished Player2 HP by 30. When Player2 goes to a view that shows his HP, the controller behind that view should have re-fetched the Player2/User2 entity before rendering the view.
In other words, all of your presentation (detached) entities should be, sort of, request-scoped.
i.e you can use a #WebListener to reload your Player/User:
#WebListener
public class CurrentUserListener implements ServletRequestListener {
#Override
public void requestInitialized(ServletRequestEvent sre) {
CurrentUser currentUser = getCurrentUser();
currentUser.reload();
}
#Override
public void requestDestroyed(ServletRequestEvent sre) {
// nothing to do
}
public CurrentUser getCurrentUser() {
// return the CurrentUser
}
}
or a request-scoped bean (or whatever-spring-equivalent):
#RequestScoped
public class RefresherBean {
#Inject
private CurrentUser currentUser;
#PostConstruct
public void init()
{
currentUser.reload();
}
}
notify other controller instances: if the update succeeded a notification should be sent to other controllers.
i.e. using CDI #Observe (if you have CDI available):
public class CurrentUser implements UserDetails {
private static final long serialVersionUID = 1L;
private User user = new User();
public CurrentUser(User user) {
this.user = user;
}
public PlayerStats getPlayerStats() {
return this.user.getStats();
}
public void onUpdate(#Observes(during = TransactionPhase.AFTER_SUCCESS) User user) {
if(this.user.getId() == user.getId()) {
this.user = user;
}
}
// removed the rest for brevity
}
Note that CurrentUser should be a server-managed object.

Why and How to mock Model-Helperclasses?

I am reading a lot about unit testing, mocking, and all that stuff. I am currently also reading the book "Growing Object-Oriented Software Guided by Tests" by Steve Freeman and Nat Pryce.
I am starting to understand a lot of stuff but missing one crucial point, where I tried to find the answer anywhere online but am not satisfied yet.
In the following example I have an Online Shop, which receives messages from a third-party library, translates those, interpret them and eventually persist them into the database if needed. In a concrete case, I receive a message about a change of the address of a credit card of a user and want to store that information into a database.
The structure looks like this:
src/
domain/
MessageTranslator.java
ShopEventListener.java
ShopHandler.java
model/
CreditCard.java
CreditCardBase.java
CreditCardBuilder.java
User.java
UserBase.java
UserBuilder.java
test/
MessageTranslatorTest.java
ShopHandlerTest.java
MessageTranslatorTest
public class MessageTranslatorTest {
#Test
public void notifiesCCAddressChangedWhenChangeCCAddressMessageReceived() throws Exception {
ShopEventListener listenerMock = mock(ShopEventListener.class);
MessageTranslator messageTranslator = new MessageTranslator(listenerMock);
messageTranslator.processMessage("action=changeCCAddress; firstname=John; lastname=Doe; address=foobar3");
verify(listenerMock).ccAddressChanged("John", "Doe", "foobar3");
}
}
MessageTranslator (very simple for now)
public class MessageTranslator {
private final ShopEventListener listener;
public MessageTranslator(ShopEventListener userEventListener) {
listener = userEventListener;
}
public void processMessage(String message) throws Exception {
String[] attributes = message.split(";");
listener.ccAddressChanged(attributes[1].split("=")[1].trim(), attributes[2].split("=")[1].trim(), attributes[3].split("=")[1].trim());
}
}
ShopHandler
public class ShopHandler implements ShopEventListener {
#Override
public void ccAddressChanged(String firstname, String lastname, String newAddress) throws Exception {
// find a user (especially userid) in the Database for given firstname and lastname
UserBase userBase = new UserBase();
User user = userBase.find(aUser().withFirstname(firstname).withLastname(lastname).build());
if (user == null) {
throw new Exception();
}
// find the matching CreditCard for the userid in the database
Integer userid = user.getUserid();
CreditCardBase ccBase = new CreditCardBase();
CreditCard cc = ccBase.find(aCreditCard().withUserid(userid).build());
if (cc == null) {
throw new Exception();
}
// change address locally and then write it back to the database
cc.setAddress(newAddress);
cc.persist();
}
}
ShopHandlerTest
public class ShopHandlerTest {
#Test
public void changesCCAddressWhenChangeCCAddressEventReceived() throws Exception {
ShopHandler shop = new ShopHandler();
shop.ccAddressChanged("John", "Doe", "foobar3");
// TODO: How to test the changes in inner object?
}
}
This is where I always stumble.
Do I want to mock the helper classes UserBase and CreditCardBase to not perform any database queries but just return a prepared fake object?
Do I want to mock the persist-method to not write any real data to the database but maybe just test the parameters of the object to be persisted and have other (integration) tests test the database operations?
If 1. and 2. will be answered with yes, then what am I actually testing here? Is it worth unittesting this unit then?
Does the structure make sense this way?
If 1. and 2. will be answered with yes, then how do I mock the inner objects? I feel like dependency injection is the wront approach here, because first its no real dependency, but some helper classes, second (and more important imo) the ShopHandler class could be flooded with dependencies, as it might need alot of different helper classes and model classes to perform all the different actions. What if I just want to update the birthdate of a user based on an external message, do I still have to path all the dependencies like CreditCardBase and stuff?
Sorry for the long post, but it would be really awesome if you could push me in the right direction.
If you need more code for the above to understand, let me know.
Do I want to mock the helper classes UserBase and CreditCardBase to not perform any database queries but just return a prepared fake object?
Looks like your "helper classes" are actually repositories/DAOs. You normally want to test your business logic separately from DAOs, without the real database access. So yes, you should probably mock these DAOs and prepare the calls to them as they would work in reality. Prepared fake object is OK in most cases. You may also want to verify that your mocked DAO was actually called.
Do I want to mock the persist-method to not write any real data to the database but maybe just test the parameters of the object to be persisted and have other (integration) tests test the database operations?
I find it a bit strange that you seem to have the persist method in your business entity. Normally DAOs implement this type of methods.
Yes, if you test business logic you should mock the persist call to DAOs as well. If you don't do this, you'll be making tests of the business logic much heavier that they should be.
Yes, you should test your DAOs as well but separately from the business logic.
If 1. and 2. will be answered with yes, then what am I actually testing here? Is it worth unittesting this unit then?
You're testing you business logic. Just what is implemented in your ccAddressChanged method. Roughly:
if the user could not be found, an exception is thrown.
if user is found but users credit card could not be found, an exception is thrown.
if both could be found then credit card is persisted with an updated address.
Does the structure make sense this way?
It is not quite what I'm used to. You seem to have data access logic in entities, then you also have this "base" helper classess...
If 1. and 2. will be answered with yes, then how do I mock the inner objects?
With "inner objects" you probaby mean these helper classes. They are actually more that "helper classes", they are DAOs providing access to the database. You can pass or inject them from the outside. Basically this is dependency injection, your business logic depends on these DAO components. If you are able to pass them from the outside then in your test you can mock DAOs and pass mocks to your business service. With DI frameworks like Spring you'll have framework support for this.
Here'a a rough sketch of how a test for your ShopHandler class could look like with Spring and Mockito:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {ShopHandler.class})
public class ShopHandlerTest {
#Autowired
private ShopHandler sut;
#MockBean
private UserRepository userRepository;
#MockBean
private CreditCardRepository creditCardRepository;
#Test(expected = UserNotFoundException.class)
public void throwsUserNotFoundExceptionIfUserIsUnknown() {
when(userRepository.findUserByFirstNameAndLastName("Scott", "Tiger").thenReturn(null);
sut.ccAddressChanged("Scott", "Tiger", "Some Address");
}
#Test
public void successFullyUpdatesCreditCardAddress() {
when(userRepository.findUserByFirstNameAndLastName("Scott", "Tiger").thenReturn(new User("userId", ...));
when(creditCardRepository.findByUserId("userId")).thenReturn(new CreditCard(...));
ArgumentCaptor<CreditCard> creditCardCaptor = ArgumentCaptor.forClass(CreditCard.class);
verify(creditCardRepository).save(creditCardCaptor.capture());
sut.ccAddressChanged("Scott", "Tiger", "Some Address");
asserthThat(creditCardCaptor.getValue().getAddress()).isEqualTo("Some Address");
}
}
I feel like dependency injection is the wront approach here,
Dependency injection is a very sensible approach here.
because first its no real dependency,
Well, of course these are real dependencies.
but some helper classes,
Where do you think it end being a "helper class" and starts being a "real dependency"? What you call "helper classes" pretty much resemble DAOs which absolutely are "real dependencies".
second (and more important imo) the ShopHandler class could be flooded with dependencies, as it might need alot of different helper classes and model classes to perform all the different actions.
If you need to perform all these actions and need all these dependencies to do this, then this is the reality. The question is, however - do you really have to implement all of these actions in just one business service? Can't you divide this into many business services? You'll get smaller more focused classes then, and they will only need a few dependencies.
Since you're creating UserBase and CreditCard instances using new keyword in the method ccAddressChanged() - you cannot mock them!
In order to be able to mock them use DI - Dependency Injection (also called IoC - Inversion Of Control) by injecting instances of these class to ccAddressChanged():
change the signature of the class from:
public void ccAddressChanged(String firstname, String lastname, String newAddress)
to:
public void ccAddressChanged(String firstname, String lastname, String newAddress, UserBase userBase, CreditCard creditCard)
This way, you'll be able to mock them (using Mockito or any other mocking framework) and sending the mocks to the method.
Example of how the test will look, using Mockito:
#Test
public void changesCCAddressWhenChangeCCAddressEventReceived() throws Exception {
ShopHandler shop = new ShopHandler();
// mock UserBase and its behavior
UserBase mockedUserBase = mock(UserBase.class)
when(mockedUserBase.find(any()).thenReturns(mock(User.class));
// mock CreditCard
CreditCard mockedCreditCard = mock(CreditCard.class);
shop.ccAddressChanged("John", "Doe", "foobar3");
}
I feel like dependency injection is the wrong approach here, because
first its no real dependency, but some helper classes, second (and
more important imo) the ShopHandler class could be flooded with
dependencies
DI is not wrong:
It seems that ShopHandler class does have a real dependency on UserBase and CreditCardBase
To avoid "flooded" scenario you can inject them into the constructor of ShopHandler and save them into private fields. This way it's done only once during initialization and does not burden the user as well as doesn't expose implementation details.
Further, assuming that you refactored your code and now you're assigning UserBase and CreditCardBase in the constructor. I would refactor the code from:
#Override
public void ccAddressChanged(String firstname, String lastname, String newAddress) throws Exception {
// find a user (especially userid) in the Database for given firstname and lastname
UserBase userBase = new UserBase();
User user = userBase.find(aUser().withFirstname(firstname).withLastname(lastname).build());
if (user == null) {
throw new Exception();
}
// find the matching CreditCard for the userid in the database
Integer userid = user.getUserid();
CreditCardBase ccBase = new CreditCardBase();
CreditCard cc = ccBase.find(aCreditCard().withUserid(userid).build());
if (cc == null) {
throw new Exception();
}
// change address locally and then write it back to the database
cc.setAddress(newAddress);
cc.persist();
}
to:
#Override
public void ccAddressChanged(String firstname, String lastname, String newAddress) throws Exception {
User user = getUserByName(firstname, lastname);
CreditCard creditCard = getCCByUser(user);
setAddress(creditCard, newAddress);
}
and now you don't have to unit-test this ccAddressChanged() anymore. What you should do is test, and each one of the three methods: getUserByName, getCCByUser and setAddress. And each one of them is easy to mock and test!
Here is how I would write integration tests for ShopHandler (as shown in the question, with no changes):
public class ShopHandlerTest {
#Tested(fullyUnitialized = true) AppDB appDB;
#Tested ShopHandler sut;
#Test(expected = UserNotFoundException.class)
public void throwsUserNotFoundExceptionIfUserIsUnknown() {
sut.ccAddressChanged("Unknown", "user", "...");
}
#Test
public void successFullyUpdatesCreditCardAddress() {
User user = new User("Scott", "Tiger");
appDB.persist(user);
CreditCard cc = new CreditCard(user, ...);
appDB.persist(cc);
String newAddress = "New address";
sut.ccAddressChanged(user.getFirstName(), user.getLastName(), newAddress);
appDB.refresh(cc);
assertEquals(newAddress, cc.getAddress());
}
}
Above, #Tested is a JMockit annotation with full DI support, and also JPA/EJB/etc. support. It can be used as a meta-annotation, so you could create a #SUT or #TestUtil annotation to simplify its use in tests.
The fully-reusable test utility class AppDB would be something like this:
public final class AppDB {
#PersistenceContext private EntityManager em;
#PostConstruct
private void startTransaction() { ... using em... }
#PreDestroy
private void endTransaction() { ... rollback using em... }
public void persist(Object entity) { em.persist(entity); }
public void refresh(Object entity) { em.refresh(entity); }
}
Notice how nice and simple those integration tests look. They basically only contain high-level code, essentially the same kind of code you would see in the production (SUT) code. No complicated mocking APIs to get you in trouble. They are also fast and stable.

How to return a "lighter" version of the data from a Controller?

I'm using Spring 4.3, and I have a REST Controller that returns a User object to the UI (javascript).
The problem is that I get a User object from the Database (say with Hibernate) that contains a password. I don't want to expose the password by actually returning it. Instead, I want the controller method to put NULL in it before returning it (I could use Optional or other solutions to avoid nulls, but I'm keeping it simple in this question).
public class User {
private String username;
private String password;
//setters and getters
}
#Controller
public class MainController {
#RequestMapping(value = "/user/getOne", method = RequestMethod.GET)
public User getOneUser() {
User user = //getUser
//something to nullify the password?
return user;
}
This question concerns a User and a password for clarity, but I'm looking for a wide solution that would take care of all my data models and the values I don't want them to include in some returns.
Solutions I don't like :)
Disliked solution #1: Remove the password in a private method or a utility class' method or an Adapter class
I don't like this because it makes the code very long. Most controller methods will need their own adaptation of the data.
I prefer something more clean and short.
Disliked solution #2: Use #JsonIgnore annotation
I don't want to bind my data models with Jackson package.
Disliked solution #3: Use a smaller data model class, and blind-copy everything that the smaller can contain
This solution refers to a code such as this:
public class ReturnUser {
private String username;
}
#Controller
public class MainController {
#RequestMapping(value = "/user/getOne", method = RequestMethod.GET)
public User getOneUser() {
User user = //getUser
ReturnUser smaller = copyWhatsInCommon(user, User.class, ReturnUser.class); //sees that there's only username common to both, so copies only it
return smaller;
This also increases the quantity of code, so I don't like it.
Any ideas?
Option 1:
You can add a transformation layer between your controller and the facade (or the service which populates the entity from the database). The transformation layer classes can convert the entities into value objects. The VOs will only contain the minimal information that your view needs. If there are more entities than 1 that you need to transform into value objects, you can also use reflections to read the properties (from a config file or something) that need to be read from the entities and copied to the VOs. However, this is not quite different from the solution 3 in your question that you don't like much. While it serves from performance and security perspective, it does add additional code in form of a transformation layer.
Option 2: An alternate and straightforward option I can propose is read the required attributes from 'User' class and populate them as model attributes.
#RequestMapping(value = "/user/getOne", method = RequestMethod.GET)
public User getOneUser(ModelMap modelMap) {
User user = //getUser
modelMap.addAttribute("userName", user.getName());
modelMap.addAttribute("userEmail", user.getEmail());
...
...
}
}
From experience:
1.) You should not return your business objects from the View layer ie Controller. You see this in many tutorials, but this is poor design.
2.) You should create a response object. This response object will only contain the fields you want to return to the user.
3.) You should instantiate the fields for UserResponse in the constructor with the user object.
Using since you are creating a resposne object, you using the #JsonIgnore annotation doesn't make sense.
While this may be more code, it is a better design with a clear separation of responsibility. The controller only needs to worry about the view object and the business layer never needs to know anything about the view.
Ex
public class UserResponse {
private String firstName;
private String lastName;
public UserResponse(User user){
this.firstName = user.getFirstName();
this.lastName = user.getLastName();
}
...
//The getters
}
In the controller:
return new UserResponse(user);
Why do you want absolutely to return the User as it is represented in your entity?
The service and the controller layers should even not get a User object that contains a password field. So your 1 and 3 solution should be avoided.
In your case returning a view of the User class seems the most relevant way to achieve your need. Just use a DTO
Either you could return the User DTO from a service layer that accesses to the Data Access layer.
Or if you don't have a service layer, you could provide a method in the data access layer that returns a User DTO without the password field.
I am going to offer one more solution. Just for coverage. This is very ugly and not recommended. You can create an object mapper and filter the object:
static ObjectMapper mapper = new ObjectMapper();
public static String filterOutAllExcept(Object obj, String filterName, String... properties) throws YpException {
mapper.registerModule(new Hibernate4Module());
SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.filterOutAllExcept(properties);
FilterProvider filterProvider = new SimpleFilterProvider().addFilter(filterName, filter).setFailOnUnknownId(false);
String strValue;
try {
strValue = mapper.writer(filterProvider).writeValueAsString(obj);
} catch (JsonProcessingException e) {
// handle exception
}
return strValue;
}
Then you can call it like:
String filterApplied = ObjectMapperHelper.filterOutAllExcept(user, JsonDTOFilter.SOMEFILTER, "firstName", "lastName");
This will give you a json string with the fields firstName and lastName

Pattern for persisting data in Realm?

My issue is how to organize the code. Let say I have a User class
public class User extends RealmObject {
#PrimaryKey
private String id;
#Required
private String name;
public User() { // per requirement of no args constructor
id = UUID.randomUUID().toString();
}
// Assume getter & setter below...
}
and a Util class is needed to handles the save in an asynchronous manner since RealmObjects cannot have methods other than getter/setter.
public class Util {
public static void save(User user, Realm realm) {
RealmAsyncTask transaction = realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
realm.copyToRealm(user); // <====== Argument needs to be declared final in parent method's argument!
}
}, null);
}
}
The intention is to put save() in a Util class to prevent spreading similar save code all over the code-base so that every time I wanted to save I would just call it as such:
User u = new User();
u.setName("Uncle Sam");
Util.save(u, Realm.getDefaultInstance());
Not sure if this affects performance at all, but I was just going to save all fields overwriting what was there except for the unique id field every single time.
The problem is that I now need to set the "user" argument as final in the Util.save() method, which means I cannot pass in the object I need to save other than once.
Is there a different way of handling this? Maybe a different pattern? Or am I looking at this all wrong and should go back to SQLite?
Why is it a problem to set public static void save(final User user, Realm realm) ? It just means you cannot reassign the user variable to something else.
That said, the existence of a save() method can be a potential code smell as you then spread the update behaviour across the code base. I would suggest looking into something like the Repository pattern (http://martinfowler.com/eaaCatalog/repository.html) instead.
Realm is actually working on an example showing how you can combine the Model-View-Presenter architecture with a Repository to encapsulate updates which is a good pattern for what you are trying to do here. You can see the code for it here: https://github.com/realm/realm-java/pull/1960

Which blocks of code should be synchronized?

I have three different classes:
Managed bean (singleton scope)
Managed bean (session scope)
Spring #Controller
I read few posts here about synchronization, but I still don't understand how it should be and how it works.
Short examples:
1) Managed bean (singleton scope).
Here all class fields should be the same for all users. All user work with one instance of this object or with his copies(???).
public class CategoryService implements Serializable {
private CategoryDao categoryDao;
private TreeNode root; //should be the same for all users
private List<String> categories = new ArrayList<String>();//should be the same for all users
private List<CategoryEntity> mainCategories = new ArrayList<CategoryEntity>();
//should be the same for all users
public void initCategories() {
//get categories from database
}
public List<CategoryEntity> getMainCategories() {
return mainCategories;
}}
2) Managed bean (session scope)
In this case, every user have his own instance of object.
When user trying to delete category he should check are another users which trying to delete the same category, so we need to use synchronized block???
public class CategoryServiceSession implements Serializable {
private CategoryDao categoryDao;
private CategoryService categoryService;
private TreeNode selectedNode;
public TreeNode getSelectedNode() {
return selectedNode;
}
public void setSelectedNode(TreeNode selectedNode) {
this.selectedNode = selectedNode;
}
public void deleteCategory() {
CategoryEntity current = (CategoryEntity) selectedNode.getData();
synchronized (this) {
//configure tree
selectedNode = null;
categoryDao.delete(current);
}
categoryService.initCategories();
}}
3) Spring #Controller
Here all user may have an instance (or each user have his own instance???). But when some admin try to change parameter of some user he should check is another admin trying to do the same operation??
#Controller
#RequestMapping("/rest")
public class UserResource {
#Autowired
private UserDao userDao;
#RequestMapping(value = "/user/{id}", method = RequestMethod.PUT)
public #ResponseBody UserEntity changeBannedStatus(#PathVariable Long id) {
UserEntity user = userDao.findById(id);
synchronized (id) {
user.setBanned(!user.getBanned());
userDao.update(user);
}
return user;
}
}
So, how it should to be?
Sorry for my English.
In the code that you've posted -- nothing in particular needs to be synchronised, and the synchronised blocks you've defined won't protect you from anything. Your controller scope is singleton by default.
If your singletons change shared objects ( mostly just their fields) then you should likely flag the whole method as synchronised.
Method level variables and final parameters will likely never need synchronization ( at least in the programming model you seem to be using ) so don't worry about it.
The session object is guarded by serialisation, mostly, but you can still have data races if your user has concurrent requests -- you'll have to imagine creative ways to deal with this.
You may/will have concurrency issues in the database ( multiple users trying to delete or modify a database row concurrently ) but this should be handled by a pessimistic or optimistic locking and transaction policy in your DAO.
Luck.
Generally speaking, using synchronized statements in your code reduces scalability. If your ever try to use multiple server instances, your synchronized will most likely be useless. Transaction semantics (using either optimistic or pessimistic locking) should be enough to ensure that your object remains consistent. So in 2 und 3 you don't need that.
As for shared variables in CategoryService it may be possible to synchronize it, but your categories seem to be some kind of cache. If this is the case, you might try to use a cache of your persistence provider (e.g. in Hibernate a second-level cache or query cache) or of your database.
Also calling categoryService.initCategories() in deleteCategory() probably means you are reloading the whole list, which is not a good idea, especially if you have many categories.

Categories