'How I can save information when I get exception in jpa
I've project with spring, spring-boot and JPA. When a user tries to log in I want to register activity in a binnacle. The authentication is with LDAP I have a new class called LoginActivity and implement an interface with only one method to save activity with annotation @Component and my method where a want to save information when user put credentials wrong I have annotation
@Transactional(propagation = Propagation.REQUIRES_NEW) And I have another method where I try to save information in my database I debug my code and it looks good and the process finished well. But when I saw my database I don't see anything I use DTO objects between classes
My method authentication:
@Override
@Transactional
public Authentication authenticate(Authentication authentication) {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
List<GrantedAuthority> authorities = (List<GrantedAuthority>) authentication.getAuthorities();
...
context = connect(user, password);//where authentication did
My DTO class, I use lombok
@Data
@Builder
public class LoginDTO {
private String user;
private String tracking;
private Map<String, Boolean> roles;
private String name;
private String lastName;
private boolean loginSuccess;
private String ipAddress;
}
I set every value in my class DTO
LoginDTO loginDTO = LoginDTO.builder()
.loginSuccess(true)
.tracking(tracking)
.lastName(lastName)
.name(name)
.roles(roles)
.user(user)
.ipAddress(httpServletRequest.getRemoteAddr())
.build();
loginActivity.saveLoginActivity(LoginDTO);
My interface
@FunctionalInterface
public interface LoginActivity {
public void saveLoginActivity(LoginDTO loginDTO);
}
My class than implement interface
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class LoginActivityImpl implements LoginActivity {
My entity
@Entity(name = "activity_desk_control")
@Setter
@Getter
public class ActivityDeskControlEntity {
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
@Basic(optional = false)
@Size(max = 255)
@Column(name = "id")
private String id;
@ManyToOne
@JoinColumn(name = "id_user_desk")
private DeskUserLogEntity idUserDesk;
@Column(name = "creation_date")
private Date creationDate;
@Column(name = "id_tracking")
private String idTracking;
@ManyToOne
@JoinColumn(name = "id_service_desk_control")
private ServiceDeskControlEntity idServiceDeskControl;
@Column(name = "params")
@Lob
private String params;
@Column(name = "url")
private String url;
@Column(name = "ip_address")
private String ipAddress;
@Column(name = "login_success")
private int loginSuccess;
@Column(name = "logout")
private int logout;
@Column(name = "logout_date")
private Date logoutDate;
}
My method where I save activity if authentication was well
public void saveMultipart(ActivityDeskControlEntity activityDeskControlEntity) {
this.activityDeskControlRepository.save(activityDeskControlEntity);
}
My method where I save activity if authentication was wrong
@Transactional(propagation = Propagation.REQUIRES_NEW)
public SimpleResponse saveMultipartLoginFail(ActivityDeskControlEntity activityDeskControlEntity) {
this.activityDeskControlRepository.save(activityDeskControlEntity);
}
Have you some idea how I can save information if I got an exception in JPA? I look some links like this but not work. My database is Oracle 19c
Update 1 The exception I get when I put credentials wrong is
javax.naming.AuthenticationException: [LDAP: error code 49 - Invalid Credentials]
In this scenario I want to save information the login fail.
Update 2
In the scenario that throws an exception is
context = connect(user, password);
For default LDAP throw an exception when user and password are wrong in consequence in this exception I want to save.
Update 3
I saw in documentation says:
Any RuntimeException or Error triggers rollback, and any checked Exception does not.
When the user put credentials wrong throw an exception that extends RuntimeException
import org.springframework.security.core.AuthenticationException;
/**
* Thrown if an authentication request is rejected because the credentials are invalid.
* For this exception to be thrown, it means the account is neither locked nor disabled.
*
* @author Ben Alex
*/
public class BadCredentialsException extends AuthenticationException {
// ~ Constructors
// ===================================================================================================
/**
* Constructs a <code>BadCredentialsException</code> with the specified message.
*
* @param msg the detail message
*/
public BadCredentialsException(String msg) {
super(msg);
}
/**
* Constructs a <code>BadCredentialsException</code> with the specified message and
* root cause.
*
* @param msg the detail message
* @param t root cause
*/
public BadCredentialsException(String msg, Throwable t) {
super(msg, t);
}
}
/**
* Abstract superclass for all exceptions related to an {@link Authentication} object
* being invalid for whatever reason.
*
* @author Ben Alex
*/
public abstract class AuthenticationException extends RuntimeException {
// ~ Constructors
// ===================================================================================================
/**
* Constructs an {@code AuthenticationException} with the specified message and root
* cause.
*
* @param msg the detail message
* @param t the root cause
*/
public AuthenticationException(String msg, Throwable t) {
super(msg, t);
}
/**
* Constructs an {@code AuthenticationException} with the specified message and no
* root cause.
*
* @param msg the detailed message
*/
public AuthenticationException(String msg) {
super(msg);
}
}
I tried to change type of exception, but I couldn't, why? spring security to expected BadCredentialsException and not my own BadCredentialsException.
Are there any way to achieve that?
Solution 1:[1]
The simplest approach would be a try catch statement since the Stacktrace for the exception is missing in your question I ave to guess that your exception is thrown in line
context = connect(user, password);//where authentication did
A solution would then be
try {
context = connect(user, password);//where authentication did
} catch (AuthenticationException e) {
log.error("User could not autheticate");
someRepository.save(CustomErrorObject);
someOtherCustomSaveMethod();
throw e;
}
the error behavior is still the same since the exception is re thrown in the catch statement, but the save code before can be executed.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
