I am making a shopping cart using a stateful session bean approach of Java EE Application. My plan is that after a user clicks on 'Checkout' button the order will be added to the database. However, the order is not updated in the database.
ShoppingCartFacade.java
#Stateful
public class ShoppingCartFacade implements ShoppingCartFacadeLocal {
#PersistenceContext(unitName = "DProject-ejbPU", type = PersistenceContextType.EXTENDED)
private EntityManager em;
private void create(Tickettable tickettable) {
em.persist(tickettable);
}
private ArrayList<Tickettable> ticketCart;
#PostConstruct
private void initializeBean(){
ticketCart = new ArrayList<>();
}
#Override
public boolean add(Tickettable tickettable) {
boolean result = false;
//Set the correct user and showtime table
tickettable.setUserid(this.getUsertableFrom(tickettable.getUserid().getUserid()));
tickettable.setShowtimeid(this.getShowtimetableFrom(tickettable.getShowtimeid().getShowtimeid()));
try {
//Already have ticket for this showtime
for (Tickettable ticket : ticketCart) {
if (ticket.getShowtimeid().getShowtimeid().equals(tickettable.getShowtimeid().getShowtimeid())) {
ticket.setQuantity(ticket.getQuantity() + tickettable.getQuantity());
result = true;
}
}
//New ticket
if (!result) {
ticketCart.add(tickettable);
result = true;
}
} catch (Exception ex) {
}
return result;
}
#Override
public ArrayList<Tickettable> getCart() {
return ticketCart;
}
#Override
public boolean checkOut() {
try {
for (Tickettable ticket : ticketCart) {
create(ticket);
}
ticketCart.clear();
return true;
} catch (Exception e) {
}
return false;
}
private Usertable getUsertableFrom(String userId) {
Usertable u = em.getReference(Usertable.class, userId);
return u;
}
private Showtimetable getShowtimetableFrom(String showtimeId) {
Showtimetable s = em.getReference(Showtimetable.class, showtimeId);
return s;
}
#Remove
public void remove() {
ticketCart = null;
}
}
ShoppingCartManagement.java
#Stateful
public class ShoppingCartManagement implements ShoppingCartManagementRemote {
#EJB
private ShoppingCartFacadeLocal shoppingCartFacade;
#Override
#PermitAll
public boolean add(TicketDTO ticketDTO) {
if (ticketDTO == null) {
// just in case
return false;
}
// convert to entity
Tickettable ticket = Utility.ticketDTO2Entity(ticketDTO);
// add one
return shoppingCartFacade.add(ticket);
}
#Override
#PermitAll
public ArrayList<TicketDTO> getCart() {
try {
ArrayList<Tickettable> alst = shoppingCartFacade.getCart();
if (alst.isEmpty()) {
//not found
return null;
} else {
ArrayList<TicketDTO> alsDTO = new ArrayList<>(alst.size());
for (Tickettable stt : alst) {
TicketDTO stDTO = Utility.ticketEntity2DTO(stt);
alsDTO.add(stDTO);
}
return alsDTO;
}
} catch (NullPointerException e) {
throw e;
}
}
#Override
#PermitAll
public boolean checkOut() {
return shoppingCartFacade.checkOut();
}
}
ShoppingCartManagedBean.java in War
#Named(value = "shoppingCartManagedBean")
#RequestScoped
public class ShoppingCartManagedBean implements Serializable{
.....
#EJB
private ShoppingCartManagementRemote shoppingCartManagement;
public String addTicket(){
this.quantity += 1;
UserDTO u = new UserDTO(userId,"","","","","");
ShowtimeDTO s = new ShowtimeDTO(showtimeId,"","","","","");
TicketDTO t = new TicketDTO("111111",u,s,Integer.toString(this.quantity));
//carts = shoppingCartManagement.getCart();
boolean result = shoppingCartManagement.add(t);
if(result){
return "success";
}
return "failure";
}
public String checkout(){
/*return shoppingCartManagement.checkOut();*/
boolean result = shoppingCartManagement.checkOut();
if(result) return "success";
return "failure";
}
}
*********************** UPDATE **********************
I just made the test. The cartList in ShoppingCartFacade.java is empty.
You need to be aware of the lifecycle management of the various beans that you're using.
#Stateful beans are not implicitly associated with the servlet/JSF session.
A new instance of ShoppingCartManagedBean will be created for each incoming request as it is #RequestScoped. This instance will automatically get a reference to a new instance of ShoppingCartManagement which will in turn get a reference to a new instance of ShoppingCartFacade.
You need to either:
Change ShoppingCartManagedBean to be #SessionScoped, or
Create an #SessionScoped facade which delegates to the ShoppingCartManagement reference and inject that in place of the EJB.
Either of these methods will associate your stateful session bean with the servlet/JSF session.
Related
I've been reading about the new Architecture Components that were introduced to Android and I cannot figure out how this works:
ViewModelProviders.of(Activity).get(Class)
Initially I thought that it calls the default constructor and returns a ViewModel object that you then instantiate with eg. an init() method as per
public class UserProfileViewModel extends ViewModel {
private String userId;
private User user;
public void init(String userId) {
this.userId = userId;
}
public User getUser() {
return user;
}
}
Snippet taken from the guide: https://developer.android.com/topic/libraries/architecture/guide.html
However, later on in the guide there is this snippet:
public class UserProfileViewModel extends ViewModel {
private LiveData<User> user;
private UserRepository userRepo;
#Inject // UserRepository parameter is provided by Dagger 2
public UserProfileViewModel(UserRepository userRepo) {
this.userRepo = userRepo;
}
public void init(String userId) {
if (this.user != null) {
// ViewModel is created per Fragment so
// we know the userId won't change
return;
}
user = userRepo.getUser(userId);
}
So how does the ViewModelProvider know to call the provided constructor? Or it sees that there is only 1 constructor and calls that? For example if there were 2 constructors what would happen?
I tried digging through the code and what I found was:
#Override
public <T extends ViewModel> T create(Class<T> modelClass) {
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.getConstructor(Application.class).newInstance(mApplication);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
return super.create(modelClass);
}
Inside of the DefaultFactory class inside ViewModelProviders.java. However, this confused me even further. How does getConstructor(Application.class) even work when ViewModel objects do not have a constructor taking an Application as an argument?
In the snippet there is a condition that checks if modelClass is of type AndroidViewModel (inherits ViewModel) which constructor takes Application parameter. This is more like exclusive case that spares the Factory of looking up for constructor matching specific parameters.
This provider looks up for constructor matching provider arguments when creating it:
public class ViewModelParameterizedProvider {
private AtomicBoolean set = new AtomicBoolean(false);
private ViewModelStore viewModelStore = null;
static ViewModelParameterizedProvider getProvider() {
return new ViewModelParameterizedProvider();
}
#MainThread
public static ViewModelProvider ofSupportFragment(Fragment fragment, Object... params) {
return getProvider().of(fragment).with(params);
}
#MainThread
public static ViewModelProvider ofActivity(FragmentActivity fragmentActivity, Object... params) {
return getProvider().of(fragmentActivity).with(params);
}
#MainThread
public static ViewModelProvider ofFragment(android.app.Fragment fragment, Object... params) {
return getProvider().of(fragment).with(params);
}
private ViewModelParameterizedProvider of(Fragment fragment) {
checkForPreviousTargetsAndSet();
viewModelStore = ViewModelStores.of(fragment);
return this;
}
private ViewModelParameterizedProvider of(android.app.Fragment fragment) {
FragmentActivity fragAct = (FragmentActivity) fragment.getActivity();
return of(fragAct);
}
private ViewModelParameterizedProvider of(FragmentActivity activity) {
checkForPreviousTargetsAndSet();
viewModelStore = ViewModelStores.of(activity);
return this;
}
private ViewModelProvider with(Object... constructorParams) {
return new ViewModelProvider(viewModelStore, parametrizedFactory(constructorParams));
}
private void checkForPreviousTargetsAndSet() {
if (set.get()) {
throw new IllegalArgumentException("ViewModelStore already has been set. Create new instance.");
}
set.set(true);
}
private ViewModelProvider.Factory parametrizedFactory(Object... constructorParams) {
return new ParametrizedFactory(constructorParams);
}
private final class ParametrizedFactory implements ViewModelProvider.Factory {
private final Object[] mConstructorParams;
ParametrizedFactory(Object... constructorParams) {
mConstructorParams = constructorParams;
}
#Override
public <T extends ViewModel> T create(Class<T> modelClass) {
if (modelClass == null) {
throw new IllegalArgumentException("Target ViewModel class can not be null")
}
Log.w("ParametrizedFactory", "Don't use callbacks or Context parameters in order to avoid leaks!!")
try {
if (mConstructorParams == null || mConstructorParams.length == 0) {
return modelClass.newInstance();
} else {
Class<?>[] classes = new Class<?>[mConstructorParams.length];
for (int i = 0; i < mConstructorParams.length; i++) {
classes[i] = mConstructorParams[i].getClass();
}
return modelClass.getConstructor(classes).newInstance(mConstructorParams);
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
}
Here is kotlin version.
Here is more read on the subject
I have configured a security-interceptor which should have the user-session object (which is a singleton) injected here is what I tried:
public DependencyInjection extends AbstractModule{
//Class that has AccessLevel Annoation
bind(InterfaceA.class).to(ImplA.class);
bind(UserPersistor.class).to(UserPersistorImpl.class);
//My session that I wish to inject
bind(UserSession.class).to(UserSessionHandler.class);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AccessLevel.class),
new SecurityInterceptor(getProvider(UserSession.class)));
}
Here my UserSessionHandler:
#Singleton
public class UserSessionHandler implements UserSession {
private UserLevel userLevel = UserLevel.DEFAULT;
private final UserPersistor userPersistor;
#Inject
public UserSessionHandler(UserPersistor userPersistor) {
this.userPersistor = userPersistor;
}
#Override
public boolean loginUser(String userName, String password) {
Benutzer user = userPersistor.getUserByName(userName);
if (user == null) {
return false;
} else {
if (user.getKennwort().equals(password)) {
userLevel = UserLevel.valueOf(user.getRolleId().getBezeichnung().toUpperCase());
return true;
} else {
return false;
}
}
}
#Override
public boolean logoutUser() {
userLevel = UserLevel.DEFAULT;
return true;
}
#Override
public UserLevel getUserLevel() {
return userLevel;
}
}
Here how the SecurityInterceptor currently looks like:
#Singleton
public class SecurityInterceptor implements MethodInterceptor {
private final Provider<UserSession> session;
#Inject
public SecurityInterceptor(Provider<UserSession> session){
this.session = session;
}
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
AccessLevel[] acessRoles = invocation.getMethod().getAnnotationsByType(AccessLevel.class);
List<UserLevel> allowedRoles = new ArrayList<>();
for(AccessLevel accessRole: acessRoles){
allowedRoles.add(accessRole.value());
}
//Make sure that User has one of the allowed Access-Levels
if (!allowedRoles.contains(session.get().getUserLevel())) {
throw new InvalidAccessException("No Access allowed with userlevel" + session.get().getUserLevel());
}
return invocation.proceed();
}
}
Now I managed to get it working in my Mockito-Test with a binding to an instance like this:
bind(MockInterface.class).to(MockClass.class);
bind(UserSession.class).toInstance(user);
bind(UserPersistor.class).toInstance(mockUserPersistor);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AccessLevel.class),
new SecurityInterceptor(getProvider(UserSession.class)));
However I don't want to create an instance myself but want the once guice is creating. How can I do that, or what am I currently doing wrong?
EDIT: My main issue is that the usersession seems to be different to the one that is generated. Here a simple example:
Injector injector = Guice.createInjector(new DependencyInjection());
UserSession session = injector.createInstance(UserSession.class);
InterfaceA methodCaller = injector.createInstance(InterfaceA.class);
if(session.loginUser("a","b")){
System.out.println(session.getUserLevel().toString()); //Returns Admin
}
methodCaller.callMethodWithAnnotation();
Now when I check the session.getUserLevel in the interceptor I get "Default"
EDIT2: My endgoal is to have the same session instance in my interceptor and anywhere I used UserSession
I'm dwelling with an autoWired service class which is null in a Spring Boot application.. Every object is instantiated by Spring, so I don't know why it happens.
The situation is:
I have a Rele.java class which is the following:
#Component
public class Rele {
private Pin pin;
private GpioController gpio;
private GpioPinDigitalOutput relePin;
private static final Logger logger = Logger.getLogger(Rele.class);
private Interruttore interruttore;
#Autowired AccensioneService accensioneService;
public Rele(){
}
// Costruttore
public Rele(Pin pin, Interruttore interruttore) {
this.pin = pin;
this.gpio = GpioFactory.getInstance();
this.relePin = gpio.provisionDigitalOutputPin(pin, "MyRele", PinState.LOW);
this.interruttore = interruttore;
}
public void lightOn() {
try {
if (relePin.isLow()) {
relePin.high();
updateAccensione(interruttore, true);
logger.debug("Rele acceso");
}
} catch (NullPointerException e) {
logger.debug("relepin è:" +relePin);
logger.debug("gpio è:"+gpio);
}
}
public void lightOff() {
if (relePin.isHigh()) {
relePin.low();
updateAccensione(interruttore, false);
logger.debug("Rele spento");
}
}
public void updateAccensione(Interruttore interruttore, boolean acceso) {
Date lastDateAccensione = new Date();
try {
logger.debug("accensioneService is"+accensioneService);
lastDateAccensione = accensioneService.findLastDate(interruttore);
} catch(NullPointerException npe){
logger.debug("accensioneService is: "+accensioneService);
logger.error("Error is:", npe);
lastDateAccensione = new Timestamp(lastDateAccensione.getTime());
}
Accensione accensione = new Accensione();
Date date = new Date();
logger.debug("lastDate:" + lastDateAccensione);
accensione.setDateTime(new Timestamp(date.getTime()));
accensione.setInterruttore(interruttore);
accensione.setIsLit(acceso);
accensione.setLastDateTime(lastDateAccensione);
logger.debug("Accensione è:"+accensione.toString());
accensioneService.saveAccensione(accensione);
}
public Pin getPin() {
return pin;
}
public void setPin(Pin pin) {
this.pin = pin;
}
public Interruttore getInterruttore() {
return interruttore;
}
public void setInterruttore(Interruttore interruttore) {
this.interruttore = interruttore;
}
public GpioPinDigitalOutput getRelePin() {
return relePin;
}
public void setRelePin(GpioPinDigitalOutput relePin) {
this.relePin = relePin;
}
public GpioController getGpio() {
return gpio;
}
public void setGpio(GpioController gpio) {
this.gpio = gpio;
}
}
When trying to call for updateAccensione, this is null.
Rele is created from a Controller, by this method
#RequestMapping(value="/illuminazione")
public ResponseEntity<Illuminazione> findIlluminazione(#RequestParam(value="idLuce") int idLuce,
#RequestParam(value="lit") boolean lit,
#RequestParam(value="suServer") boolean suServer) {
Illuminazione illuminazione = new Illuminazione();
Date lastDate = illuminazioneService.findLastDate(idLuce);
illuminazione.setLastDateTime(lastDate);
illuminazione.setIdLuce(idLuce);
illuminazione.setIsLit(lit);
Date date = new Date();
illuminazione.setDateTime(new Timestamp(date.getTime()));
illuminazioneService.saveIlluminazione(illuminazione);
logger.debug("Aggiornata luce " + idLuce + " accesa: "+lit);
//managing rele
if(suServer){
//check if status has changed
Luce luce = luceService.findById(idLuce);
int idInterruttore = luce.getInterruttore().getIdInterruttore();
Interruttore interruttore = interruttoreService.findById(idInterruttore);
Rele rele = releService.findByInterruttore(interruttore);
logger.debug("rele="+rele.toString());
if(lit){
rele.lightOn();
} else {
rele.lightOff();
}
}
return new ResponseEntity<Illuminazione>(illuminazione,HttpStatus.OK);
}
Rele is created, i find it in my logs.
AccensioneService is an interface, it's concrete implementation is AccensioneServiceImpl:
#Service("accensioneService")
#Transactional
public class AccensioneServiceImpl implements AccensioneService{
#Autowired AccensioneDao dao;
#Override
public void saveAccensione(Accensione accensione) {
dao.saveAccensione(accensione);
}
#Override
public Accensione findById(int id) {
return dao.findById(id);
}
#Override
public Date findLastDate(Interruttore interruttore) {
return dao.findLastDate(interruttore);
}
#Override
public boolean findLastStatus(int id) {
return dao.findLastStatus(id);
}
#Override
public void updateAccensione(Interruttore interruttore) {
}
}
I don't know if anything else is needed. AccensioneService is also called in other methods and controller, and it works... only when called inside Rele gives me this error...
Edited to add
You must be calling new Rele() or the other Rele(Pin, Interruttore ) constructor? If you are calling these in your code, the accensioneService will be null because Spring needs to create the bean, you cannot create it with its constructor if you want beans Autowired into it or for it to be Autowired. If you want it to behave like this, Spring has to know about it, so it has to be in (and come from) the Spring context.
Put a log statement in each constructor and find out who is calling them, and fix that so that instead of calling the constructor, you get the bean from Spring.
Old answer below
You need to post this method to be sure:
Rele rele = releService.findByInterruttore(interruttore);
I'll bet you are creating rele somewhere by calling new Rele(), which is not correct. You need to let Spring create it for you.
You did not post enough code to give further suggestions.
Also, you say this is null. What this are you talking about?
Consider the following JMX code:
public class UserJMXBeanExpose {
private UserJMXBeanImpl userJMXBean;
#Required
public void setUserJMXBean(UserJMXBeanImpl userJMXBean) {
this.userJMXBean = userJMXBean;
}
public void init() throws MBeanRegistrationException, InstanceAlreadyExistsException, NotCompliantMBeanException, MalformedObjectNameException {
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
ObjectName objectName = new ObjectName("MineStar:type=UserJMXBeanExpose,name=Statistics");
MineStarMBean impl = new MineStarMBean();
impl.addProperty(new PropertyAdapter("User", "User List", "java.lang.String") {
public Object getValue() {
if (userJMXBean == null) return 0;
return userJMXBean.getUserAttributes();
}
});
server.registerMBean(impl, objectName);
}
}
And this code:
public class UserJMXBeanImpl implements UserJMXBean {
private List<User> userList = new ArrayList<>();
public void addUser(User user){
userList.add(user);
}
public List<User> getUserList() {
return userList;
}
public void setUserList(List<User> userList) {
this.userList = userList;
}
public String[] getUserAttributes(){
for(User user : this.getUserList()){
return new String[]{user.getUserId(),user.getRoles()};
}
return null;
}
}
How can I add a listener to JMX so that it updates the values of getUserAttributes() with the newly added user by UserJMXBeanImpl class?
I need to update my jmx information when each new user is added to the impl class. Or how can we add listener so that it can notify the UserJMXBeanExpose to expose its data whenever a new user is added to impl class?
I have already asked this question two times, but I'm new to stackoverflow and it seems that I don't know the rules for formatting my example code in here. Now I've decided to give the full stack of the calls and I hope I can explain the situation because everything is so strange and I can't find the words to describe it. First I will give you the source of the classes that have something to do with the problem. My actual question is in the end of the page. The large piece of code is just in case, because I don't know what could be the explanation of my problem.
Here is a service facade that gets calls from my flex application.
public class ServiceFacade implements IAuthenticationService, IProfileService, ICampaignService {
#Autowired
private IAuthenticationService authenticationService;
#Autowired
private IProfileService profileService;
#Autowired
private ICampaignService campaignService;
public void login(User user) throws AuthenticationException{
authenticationService.login(user);
}
#Override
public void logout() throws AuthenticationException {
authenticationService.logout();
}
#Override
public void sendForgottenPassword(String email) {
authenticationService.sendForgottenPassword(email);
}
#Override
public Profile getProfile(Long userId) {
return profileService.getProfile(userId);
}
#Override
public Profile updateProfile(Profile profile) {
return profileService.updateProfile(profile);
}
#Override
public Collection<String> getSocialConnectionsTypes(Long userId) {
return profileService.getSocialConnectionsTypes(userId);
}
#Override
public List<Email> findDuplicateEmails(Long profileId, List<Email> emails) {
return profileService.findDuplicateEmails(profileId, emails);
}
#Override
public Campaign getCampaign(Long campaignId) {
return campaignService.getCampaign(campaignId);
}
#Override
public Campaign updateCampaign(Campaign campaign) {
return campaignService.updateCampaign(campaign);
}
#Override
public void removeCampaign(Long campaignId) {
campaignService.removeCampaign(campaignId);
}
#Override
public void setPools(Long campaignId, Collection<Pool> pools) {
campaignService.setPools(campaignId, pools);
}
#Override
public void addPool(Long campaignId, Pool pool) {
campaignService.addPool(campaignId, pool);
}
#Override
public void removePool(Long campaignId, Pool pool) {
campaignService.removePool(campaignId, pool);
}
#Override
public List<Campaign> getCampaigns() {
return campaignService.getCampaigns();
}
#Override
public void updatePool(Long campaignId, Pool pool) {
campaignService.updatePool(campaignId, pool);
}
}
The method which is important for my question is the findDuplicateEmails method.
The profileService is implemented in the following class:
public class ProfileService implements IProfileService {
#Autowired
private IProfileManager profileManager;
#Override
public Profile getProfile(Long userId) {
return profileManager.getProfile(userId);
}
#Override
public Profile updateProfile(Profile profile){
profileManager.updateProfile(profile);
return profile;
}
#Override
public Collection<String> getSocialConnectionsTypes(Long userId) {
return profileManager.getSocialConnectionsTypes(userId);
}
#Override
public List<Email> findDuplicateEmails(Long profileId, List<Email> emails) {
return profileManager.findDuplicateEmails(profileId, emails);
}
}
Again the important method is findDuplicateEmails
The implementation of the profileManager is the following class:
public class ProfileManager implements IProfileManager {
#Autowired
private IProfileDao profileDao;
#Autowired
private ISectionManager autoCompleteManager;
#Autowired
private IUserSecurityService userSecurityService;
#Transactional
public Profile getProfile(Long userId) {
return profileDao.getProfileByUser(userId);
}
#Transactional
public void updateProfile(final Profile profile) {
List<Major> notApprovedMajors = extractNotApprovedMajors(profile);
List<Degree> notApprovedDegrees = extractNotApprovedDegrees(profile);
List<School> notApprovedSchools = extractNotApprovedSchools(profile);
List<Language> notApprovedLanguages = extractNotApprovedLanguages(profile);
List<Position> notApprovedPositions = extractNotApprovedPositions(profile);
List<Company> notApprovedCompanies = extractNotApprovedCompanies(profile);
List<Country> notApprovedCountries = extractNotApprovedCountries(profile);
List<City> notApprovedCities = extractNotApprovedCities(profile);
List<Certificate> notApprovedCertificates = extractNotApprovedCertificates(profile);
autoCompleteManager.updateAll(notApprovedMajors);
autoCompleteManager.updateAll(notApprovedDegrees);
autoCompleteManager.updateAll(notApprovedSchools);
autoCompleteManager.updateAll(notApprovedLanguages);
autoCompleteManager.updateAll(notApprovedPositions);
autoCompleteManager.updateAll(notApprovedCompanies);
autoCompleteManager.updateAll(notApprovedCountries);
autoCompleteManager.updateAll(notApprovedCities);
autoCompleteManager.updateAll(notApprovedCertificates);
profileDao.updateProfile(profile);
}
#Override
public List<Email> findDuplicateEmails(Long profileId, List<Email> emails) {
Profile persistedProfile = profileDao.findById(profileId);
if (persistedProfile.getContact() == null)
{
persistedProfile.setContact(new Contact());
}
List<Email> resultEmails = new ArrayList<Email>();
for (int i = 0; i < emails.size(); i++) {
if ((!userSecurityService.guaranteeUniquePrincipal(emails.get(i)) &&
!isPersistedInThePersistentCollection(emails.get(i), persistedProfile.getContact().getEmails())) ||
isDuplicateInTheCurrentCollection(emails.get(i), emails, i + 1)) {
resultEmails.add(emails.get(i));
}
}
return resultEmails;
}
private boolean isDuplicateInTheCurrentCollection(Email emailToCheck, List<Email> emails, int index)
{
for (int i = index ; i < emails.size(); i ++) {
if (emails.get(i).getEmailAddress().equals(emailToCheck.getEmailAddress())) {
return true;
}
}
return false;
}
private boolean isPersistedInThePersistentCollection(Email emailToCheck, Collection<Email> emails)
{
if (emails == null) {
return false;
}
for (Email persistedEmail : emails) {
if (persistedEmail.getEmailAddress().equalsIgnoreCase(emailToCheck.getEmailAddress())) {
return true;
}
}
return false;
}
}
Again the important method is the method findDuplicateEmails
Now, after this short background, here is my problem:
I am using Hibernate with spring's HibernateTemplate. I found out that in the method findDuplicateEmails, some completely new entities which come form the flex application gets saved automatically. This was very strange and during the debbugging I found out that even if I change the method findDuplicateEmails in the ProfileManager so it looks like:
#Override
public List<Email> findDuplicateEmails(Long profileId, List<Email> emails) {
Email email = new Email();
return null;
}
the entity email gets saved automatically. I also found out that if the identifier of the entity is not "email", but something else, like "newEmail", or "email1", or something, there is no problem and the entity gets persisted if and only if I make it persistent. This problem exists only in this class and finally, this problem shows up only for the Email. I mean that if I have Phone phone = new Phone(); the entity phone gets persisted only when I wish.
The flex application first checks that the entered from the user emails are unique, and then after some user interaction calls the method updateProfile() if the entered data is valid.
I would download Hibernate sources and start debugging, you will either find a bug in Hibernate (happens) or in your code, as this is one weird behavior.
This is an advice I got once, and was the fastest, most educating way to get to the root.