Spring Security login always returns with a 302 redirect to the failureUrl - authentication

I created a project in Spring Security and React, I set up the security configuration, and I created a password encoder, the endpoints work but the login always returns me with a 302 redirect to the failureUrl.
This is some parts of source code
this is a part of SecurityConfiguration.java
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity( prePostEnabled = true )
public class SecurityConfiguration {
private final CustomerServiceImplementation customerService;
public SecurityConfiguration( CustomerServiceImplementation service ) {
this.customerService = service;
}
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return (
http
.cors()
.and()
.csrf( csrf -> csrf.disable() )
.authorizeRequests( auth ->
auth
.antMatchers("/api/v1/customer/signup").permitAll()
.antMatchers("/api/v1/role").permitAll()
// public routes
.antMatchers("/public").permitAll()
.antMatchers("/public/**").permitAll()
// FrontEnd
.antMatchers("/").permitAll()
.antMatchers("/**/*.png").permitAll()
.anyRequest().authenticated()
)
.formLogin()
.usernameParameter("email")
.passwordParameter("password")
.loginPage("/public/sign-in")
.loginProcessingUrl("/public/login")
.permitAll()
.successHandler( authenticationSuccessHandler() )
.defaultSuccessUrl("/")
.failureHandler( authenticationFailureHandler() )
.failureUrl("/public/sign-in?error=true")
.permitAll()
.and()
.logout()
.logoutUrl("/sign-out")
.logoutSuccessUrl("/")
.permitAll()
.userDetailsService( customerService )
.exceptionHandling( ex ->
ex
.accessDeniedHandler( accessDeniedHandler() )
)
.headers(headers -> headers.frameOptions().sameOrigin())
.httpBasic(withDefaults())
.build()
);
}
#Bean
public AuthenticationFailureHandler authenticationFailureHandler() {
return new AppAuthenticationFailureHandler();
}
#Bean
public AuthenticationSuccessHandler authenticationSuccessHandler() {
return new AppAuthenticationSuccessHandler();
}
#Bean
public AccessDeniedHandler accessDeniedHandler() {
return new AppAccessDeniedHandler();
}
}
this is a part of CustomerServiceImplementation.java
#Service
public class CustomerServiceImplementation implements CustomerService, UserDetailsService {
#Autowired
private CustomerRepository customerRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return
customerRepository
.findByEmail( username )
.map( Customer::new )
.orElseThrow( () -> new UsernameNotFoundException("email not exist") )
;
}
}
this is a part of Customer.java
#Data
#AllArgsConstructor
#Entity
#Table( name = "customers" )
public class Customer implements UserDetails {
#Id
#GeneratedValue( strategy = GenerationType.SEQUENCE )
private Long id;
#Column(
unique = true,
nullable = false,
length = 255
)
private String email;
#Column( nullable = false, length = 128 )
private String password;
private String phoneNumber;
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
#Column( nullable = false )
private LocalDate dob;
public Customer() {
}
public Customer(Customer customer) {
this.id = customer.getId();
this.email = customer.getEmail();
this.dob = customer.getDob();
this.roles = customer.getRoles();
}
#ManyToMany(
fetch = FetchType.EAGER
// cascade = CascadeType.ALL
)
#JoinTable(
name = "customers_roles",
joinColumns = #JoinColumn( name = "customer_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn( name = "role_id", referencedColumnName = "id")
)
private Collection<Role> roles;
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
getRoles()
.stream()
.map( role -> role.getName() )
.forEach( roleName -> {
authorities.add( new SimpleGrantedAuthority( roleName ));
})
;
return authorities;
}
}

Related

How to handle "TokenEndpoint : Handling error: InvalidScopeException, Empty scope.."?

everyone!
I've tried to repeat this tutorial https://www.youtube.com/watch?v=wxebTn_a930 to create an Authorization Server and i've received:
"Handling error: InvalidScopeException, Empty scope (either the client or the user is not allowed the requested scopes)" and I don't know why?
So i can't receive an access token from my auth server.
The only difference in my project i use postgreSQL instead of MySQL.
Project has as dependencies: spring boot starter web, spring boot starter cloud security, spring data jpa, spring cloud starter oauth2, postgresql.
Aplication.yml
server:
port: 9020
spring:
datasource:
url: jdbc:postgresql://localhost:5432/oauth
username: root
password: root
driverClassName: org.postgresql.Driver
platform: postgres
initialization-mode: never
# JPA config
jpa:
database: POSTGRESQL
hibernate.ddl-auto: validate
check-user-scopes: true
Models:
#MappedSuperclass
public class BaseIdEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
protected int id;
}
#Entity(name = "permission")
public class Permission extends BaseIdEntity {
private String name;
// Getters and Setters
}
#Entity(name = "role")
public class Role extends BaseIdEntity {
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "permission_role", joinColumns = {
#JoinColumn(name = "role_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "permission_id", referencedColumnName = "id")})
private List<Permission> permissions;
private String name;
// Getters and Setters
}
#Entity(name = "users")
public class User extends BaseIdEntity implements UserDetails {
private static final long serialVersionUID = 1L;
private String email;
private String username;
private String password;
private boolean enabled;
#Column(name = "account_locked")
private boolean accountNonLocked;
#Column(name = "account_expired")
private boolean accountNonExpired;
#Column(name = "credentials_expired")
private boolean credentialsNonExpired;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "role_user", joinColumns = {
#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "role_id", referencedColumnName = "id")})
private List<Role> roles;
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<GrantedAuthority> authorities = new HashSet<>();
roles.forEach(role -> {
authorities.add(new SimpleGrantedAuthority(role.getName()));
role.getPermissions().forEach(permission -> {
authorities.add(new SimpleGrantedAuthority(permission.getName()));
});
});
return null;
}
#Override
public String getPassword() {
return password;
}
#Override
public String getUsername() {
return username;
}
#Override
public boolean isAccountNonExpired() {
return accountNonExpired;
}
#Override
public boolean isAccountNonLocked() {
return accountNonLocked;
}
#Override
public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}
#Override
public boolean isEnabled() {
return enabled;
}
public String getEmail() {
return email;
}
}
Repository:
#Repository
#Transactional
public interface UserRepository extends JpaRepository<User, Long> {
User findUserByUsername(String username);
}
Class CustomUserDetailsService which implements UserDetailsService and overrides all methods.
#Service(value = "userDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findUserByUsername(username);
if (user == null)
throw new BadCredentialsException("Bad Credentials");
new AccountStatusUserDetailsChecker().check(user);
return user;
}
}
Web security configurations.
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(encoder());
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().exceptionHandling()
.authenticationEntryPoint((httpServletRequest, httpServletResponse, authException) ->
httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and().authorizeRequests().antMatchers("/**")
.authenticated().and().httpBasic();
}
}
Class CustomTokenEnhancer which adds additional information about user like email.
public class CustomTokenEnhancer extends JwtAccessTokenConverter {
#Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
User user = (User) authentication.getPrincipal();
Map<String, Object> info = new LinkedHashMap<>(accessToken.getAdditionalInformation());
info.put("email", user.getEmail());
DefaultOAuth2AccessToken customAccessToken = new DefaultOAuth2AccessToken(accessToken);
customAccessToken.setAdditionalInformation(info);
return super.enhance(customAccessToken, authentication);
}
}
CustomOauth2RequestFactory represents a filter which creates a token requests before any user requests.
public class CustomOauth2RequestFactory extends DefaultOAuth2RequestFactory {
#Autowired
private TokenStore tokenStore;
#Autowired
UserDetailsService userDetailsService;
public CustomOauth2RequestFactory(ClientDetailsService clientDetailsService) {
super(clientDetailsService);
}
#Override
public TokenRequest createTokenRequest(Map<String, String> requestParameters, ClientDetails authenticatedClient) {
if (requestParameters.get("grant_type").equals("refresh_token")) {
OAuth2Authentication authentication = tokenStore.readAuthenticationForRefreshToken(
tokenStore.readRefreshToken(requestParameters.get("refresh_token")));
SecurityContextHolder.getContext()
.setAuthentication(new UsernamePasswordAuthenticationToken(authentication.getName(), null,
userDetailsService.loadUserByUsername(authentication.getName()).getAuthorities()));
}
return super.createTokenRequest(requestParameters, authenticatedClient);
}
}
And configurations for authorization server.
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Value("${check-user-scopes}")
private Boolean checkUserScopes;
#Autowired
private DataSource dataSource;
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private ClientDetailsService clientDetailsService;
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Bean
public OAuth2RequestFactory requestFactory() {
CustomOauth2RequestFactory requestFactory = new CustomOauth2RequestFactory(clientDetailsService);
requestFactory.setCheckUserScopes(true);
return requestFactory;
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
#Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new CustomTokenEnhancer();
converter.setKeyPair(
new KeyStoreKeyFactory(new ClassPathResource("jwt.jks"),
"password".toCharArray()).getKeyPair("jwt"));
return converter;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource).passwordEncoder(passwordEncoder);
}
#Bean
public TokenEndpointAuthenticationFilter tokenEndpointAuthenticationFilter() {
return new TokenEndpointAuthenticationFilter(authenticationManager, requestFactory());
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore()).tokenEnhancer(jwtAccessTokenConverter())
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
if (checkUserScopes)
endpoints.requestFactory(requestFactory());
}
}
scheme-postgres.sql.
DROP TABLE IF EXISTS oauth_client_details CASCADE;
CREATE TABLE oauth_client_details(
client_id VARCHAR(255) NOT NULL PRIMARY KEY,
client_secret VARCHAR(255) NOT NULL,
resource_ids VARCHAR(255) DEFAULT NULL,
scope VARCHAR(255) DEFAULT NULL,
authorized_grant_types VARCHAR(255) DEFAULT NULL,
web_server_redirect_uri VARCHAR(255) DEFAULT NULL,
authorities VARCHAR(255) DEFAULT NULL,
access_token_validity INT DEFAULT NULL,
refresh_token_validity INT DEFAULT NULL,
additional_information VARCHAR(4096) DEFAULT NULL,
autoapprove VARCHAR(255) DEFAULT NULL);
DROP TABLE IF EXISTS permission CASCADE;
CREATE TABLE permission (
id int PRIMARY KEY,
name VARCHAR(60) UNIQUE);
DROP TABLE IF EXISTS role CASCADE;
CREATE TABLE role
(id int PRIMARY KEY,
name VARCHAR(60) UNIQUE);
DROP TABLE IF EXISTS permission_role CASCADE;
CREATE TABLE permission_role(
permission_id int,
FOREIGN KEY(permission_id) REFERENCES permission(id),
role_id int,
FOREIGN KEY(role_id) REFERENCES role(id));
DROP TABLE IF EXISTS users CASCADE;
CREATE TABLE users (
id int PRIMARY KEY,
username VARCHAR(24) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
enabled boolean NOT NULL,
account_locked boolean NOT NULL,
account_expired boolean NOT NULL,
credentials_expired boolean NOT NULL);
DROP TABLE IF EXISTS role_users CASCADE;
CREATE TABLE role_users (role_id int,FOREIGN KEY(role_id) REFERENCES role(id),
users_id int, FOREIGN KEY(users_id) REFERENCES users(id));
data-postgres.sql
INSERT INTO oauth_client_details (
client_id,client_secret,
resource_ids,
scope,
authorized_grant_types,
web_server_redirect_uri,authorities,
access_token_validity,refresh_token_validity,
additional_information,autoapprove)
VALUES(
'USER_CLIENT_APP','{bcrypt}$2a$10$EOs8VROb14e7ZnydvXECA.4LoIhPOoFHKvVF/iBZ/ker17Eocz4Vi',
'USER_CLIENT_RESOURCE,USER_ADMIN_RESOURCE',
'role_admin,role_user',
'authorization_code,password,refresh_token,implicit',
NULL,NULL,
900,3600,
'{}',NULL);
INSERT INTO permission (name) VALUES
('can_create_user'),
('can_update_user'),
('can_read_user'),
('can_delete_user');
INSERT INTO role (name) VALUES
('role_admin'),('role_user');
INSERT INTO permission_role (permission_id, role_id) VALUES
(1,1), /* can_create_user assigned to role_admin */
(2,1), /* can_update_user assigned to role_admin */
(3,1), /* can_read_user assigned to role_admin */
(4,1), /* can_delete_user assigned to role_admin */
(3,2); /* can_read_user assigned to role_user */
INSERT INTO users (
username,password,
email,enabled,account_locked, account_expired,credentials_expired) VALUES (
'admin','{bcrypt}$2a$10$EOs8VROb14e7ZnydvXECA.4LoIhPOoFHKvVF/iBZ/ker17Eocz4Vi',
'william#gmail.com',true,true,true,true),
('user','{bcrypt}$2a$10$EOs8VROb14e7ZnydvXECA.4LoIhPOoFHKvVF/iBZ/ker17Eocz4Vi',
'john#gmail.com',true,true,true,true);
INSERT INTO role_users (role_id, users_id)
VALUES
(1, 1) /* role_admin assigned to admin user */,
(2, 2) /* role_user assigned to user user */ ;
The problem was in model "User":
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<GrantedAuthority> authorities = new HashSet<>();
roles.forEach(role -> {
authorities.add(new SimpleGrantedAuthority(role.getName()));
role.getPermissions().forEach(permission -> {
authorities.add(new SimpleGrantedAuthority(permission.getName()));
});
});
return null;
}
The method returned "null" instead of "authorities". Silly mistake.

AspNetCore 2 oData - Missing context on get all identity users

I trying to create a web api with oData v4.
Now i try to get all Identity-User over oData.
This is working:
[EnableQuery]
public class UsersController : Controller
{
protected readonly UserManager<User> _userManager;
public UsersController(UserManager<User> userManager)
{
_userManager = userManager;
}
private static List<User> _users = new List<User>
{
new User { Id = 1, Name = "Flo", Email = ""},
new User { Id = 2, Name = "Felix", Email = ""},
new User { Id = 3, Name = "Andreas", Email = ""},
new User { Id = 4, Name = "Marco", Email = ""}
};
public IQueryable<User> Get()
{
return _users.AsQueryable();
}
}
And return this response:
{"#odata.context":"http://localhost:55503/oData/$metadata#Users(Id)","value":[{"Id":1},{"Id":2},{"Id":3},{"Id":4}]}
When i change the controller to return all Identity-Users this isn't working correctly.
[EnableQuery]
public class UsersController : Controller
{
protected readonly UserManager<User> _userManager;
public UsersController(UserManager<User> userManager)
{
_userManager = userManager;
}
public IQueryable<User> Get()
{
return _userManager.Users.AsQueryable();
}
}
And it returns this response:
[{"Id":"35909773-8b53-4d68-a770-b7cdfcffd0de"}]
But the response is missing the context. Can you give my a hint why?
I solved the problem:
var builder = new ODataConventionModelBuilder(serviceProvider);
builder.EntitySet<User>("Users");
return builder.GetEdmModel();

Hazelcast: Does Portable Serialization needs objects to be shared between client and server?

I am getting the below exception:
Could not find PortableFactory for factory-id: 1
com.hazelcast.nio.serialization.HazelcastSerializationException: Could
not find PortableFactory for factory-id: 1
On the client side I have the following code:
public class ClientTest {
public static void main(String[] args) {
List<String> nodes = new ArrayList<String>();
nodes.add("localhost:5701");
ClientConfig clientConfig = new ClientConfig();
ClientNetworkConfig networkConfig = new ClientNetworkConfig();
networkConfig.setAddresses(nodes);
clientConfig.setNetworkConfig(networkConfig);
SerializationConfig serCong = clientConfig.getSerializationConfig();
serCong.addPortableFactory(1, new UserFactoryImpl());
serCong.setPortableVersion(1);
HazelcastInstance hzClient1 = HazelcastClient.newHazelcastClient(clientConfig);
IMap<String, User> map = hzClient1.getMap("user");
System.out.println(map.size() + "hiten");
User user1 = new User();
user1.setFirstName("hiten");
user1.setLastName("singh");
map.put("1", user1);
//hz1.getLifecycleService().terminate();
System.out.println(map.size() + "after");
User user2 = new User();
user2.setFirstName("hiten1");
user2.setLastName("singh1");
map.put("2", user2);
UserEntryProcessor entryProc = new UserEntryProcessor();
User userRes = (User)map.executeOnKey("1", entryProc);
}
static class UserEntryProcessor implements EntryProcessor<String, User>, HazelcastInstanceAware {
private transient HazelcastInstance hazelcastInstance;
#Override
public Object process(Entry<String, User> entry) {
User user = entry.getValue();
if(user != null) {
System.out.println(user.getFirstName());
}
return user;
}
#Override
public EntryBackupProcessor<String, User> getBackupProcessor() {
return null;
}
#Override
public void setHazelcastInstance(HazelcastInstance hazelcastInstance) {
this.hazelcastInstance = hazelcastInstance;
}
}
static class UserFactoryImpl implements PortableFactory{
public final static int USER_PORTABLE_ID = 1;
public final static int FACTORY_ID = 1;
public Portable create(int classId) {
switch (classId) {
case USER_PORTABLE_ID:
return new User();
}
return null;
}
}
static class User implements Portable {
private String firstName;
private String lastName;
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#Override
public int getFactoryId() {
return UserFactoryImpl.FACTORY_ID;
}
#Override
public int getClassId() {
return UserFactoryImpl.USER_PORTABLE_ID;
}
#Override
public void writePortable(PortableWriter writer) throws IOException {
writer.writeUTF("first_name", firstName);
writer.writeUTF("last_name", lastName);
}
#Override
public void readPortable(PortableReader reader) throws IOException {
firstName = reader.readUTF("first_name");
lastName = reader.readUTF("last_name");
}
}
}
Yes it does, just as you figured out the factory and the classes need to be available. Currently there is no built-in solution to not share classes for more sophisticated use cases than simple gets / puts. I have JSON support and some other ideas cooking but nothing really done yet.

Embedded Neo4j delete node and Lucene legacy indexing - node_auto_indexing out of sync issue

I'm trying to delete node with fields in node_auto_indexing.
When I try to delete node using repository.delete(id).
Right after that I'm trying to get deleted Node by its id and I get following exception:
java.lang.IllegalStateException: This index (Index[__rel_types__,Relationship]) has been marked as deleted in this transaction
at org.neo4j.index.impl.lucene.LuceneTransaction$DeletedTxDataBoth.illegalStateException(LuceneTransaction.java:475)
at org.neo4j.index.impl.lucene.LuceneTransaction$DeletedTxDataBoth.removed(LuceneTransaction.java:470)
at org.neo4j.index.impl.lucene.LuceneTransaction.remove(LuceneTransaction.java:112)
at org.neo4j.index.impl.lucene.LuceneXaConnection.remove(LuceneXaConnection.java:116)
at org.neo4j.index.impl.lucene.LuceneIndex.remove(LuceneIndex.java:215)
at org.springframework.data.neo4j.support.typerepresentation.AbstractIndexBasedTypeRepresentationStrategy.remove(AbstractIndexBasedTypeRepresentationStrategy.java:113)
at org.springframework.data.neo4j.support.typerepresentation.AbstractIndexBasedTypeRepresentationStrategy.preEntityRemoval(AbstractIndexBasedTypeRepresentationStrategy.java:100)
at org.springframework.data.neo4j.support.mapping.EntityRemover.removeRelationship(EntityRemover.java:63)
at org.springframework.data.neo4j.support.mapping.EntityRemover.removeNode(EntityRemover.java:51)
at org.springframework.data.neo4j.support.mapping.EntityRemover.removeNodeEntity(EntityRemover.java:45)
at org.springframework.data.neo4j.support.mapping.EntityRemover.remove(EntityRemover.java:85)
at org.springframework.data.neo4j.support.Neo4jTemplate.delete(Neo4jTemplate.java:267)
at org.springframework.data.neo4j.repository.AbstractGraphRepository.delete(AbstractGraphRepository.java:276)
at org.springframework.data.neo4j.repository.AbstractGraphRepository.delete(AbstractGraphRepository.java:282)
Also, when I'm trying to delete node via Cypher query
#Query("MATCH ()-[r]-(p:Product) WHERE id(p) = {productId} DELETE r, p")
void deleteProduct(#Param("productId") Long productId);
I'm getting another exception after looking this deleted Node by its Id:
java.lang.IllegalStateException: No primary SDN label exists .. (i.e one starting with _)
at org.springframework.data.neo4j.support.typerepresentation.LabelBasedNodeTypeRepresentationStrategy.readAliasFrom(LabelBasedNodeTypeRepresentationStrategy.java:126)
at org.springframework.data.neo4j.support.typerepresentation.LabelBasedNodeTypeRepresentationStrategy.readAliasFrom(LabelBasedNodeTypeRepresentationStrategy.java:39)
at org.springframework.data.neo4j.support.mapping.TRSTypeAliasAccessor.readAliasFrom(TRSTypeAliasAccessor.java:36)
at org.springframework.data.neo4j.support.mapping.TRSTypeAliasAccessor.readAliasFrom(TRSTypeAliasAccessor.java:26)
at org.springframework.data.convert.DefaultTypeMapper.readType(DefaultTypeMapper.java:102)
at org.springframework.data.convert.DefaultTypeMapper.getDefaultedTypeToBeUsed(DefaultTypeMapper.java:165)
at org.springframework.data.convert.DefaultTypeMapper.readType(DefaultTypeMapper.java:142)
at org.springframework.data.neo4j.support.mapping.Neo4jEntityConverterImpl.read(Neo4jEntityConverterImpl.java:78)
at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister$CachedConverter.read(Neo4jEntityPersister.java:170)
at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister.createEntityFromState(Neo4jEntityPersister.java:189)
at org.springframework.data.neo4j.support.Neo4jTemplate.createEntityFromState(Neo4jTemplate.java:224)
at org.springframework.data.neo4j.repository.AbstractGraphRepository.createEntity(AbstractGraphRepository.java:62)
at org.springframework.data.neo4j.repository.AbstractGraphRepository.findOne(AbstractGraphRepository.java:127)
at org.springframework.data.neo4j.repository.AbstractGraphRepository.delete(AbstractGraphRepository.java:282)
How to correctly delete node that participates in Lucene Legacy Indexing node_auto_indexing ? How to remove this Node from Lucene index ?
UPDATED:
This is my Neo4jConfig:
#Configuration
#EnableNeo4jRepositories(basePackages = "com.example")
#EnableTransactionManagement
public class Neo4jConfig extends Neo4jConfiguration implements BeanFactoryAware {
#Resource
private Environment environment;
private BeanFactory beanFactory;
public Neo4jConfig() {
setBasePackage("com.example");
}
#Bean(destroyMethod = "shutdown")
public GraphDatabaseService graphDatabaseService() {
GraphDatabaseService graphDb = new GraphDatabaseFactory()
.newEmbeddedDatabaseBuilder("target/example-test-db")
.setConfig(GraphDatabaseSettings.node_keys_indexable, "name,description")
.setConfig(GraphDatabaseSettings.node_auto_indexing, "true")
.newGraphDatabase();
return graphDb;
}
/**
* Hook into the application lifecycle and register listeners that perform
* behaviour across types of entities during this life cycle
*
*/
#Bean
protected ApplicationListener<BeforeSaveEvent<BaseEntity>> beforeSaveEventApplicationListener() {
return new ApplicationListener<BeforeSaveEvent<BaseEntity>>() {
#Override
public void onApplicationEvent(BeforeSaveEvent<BaseEntity> event) {
BaseEntity entity = event.getEntity();
if (entity.getCreateDate() == null) {
entity.setCreateDate(new Date());
} else {
entity.setUpdateDate(new Date());
}
}
};
}
#Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
public BeanFactory getBeanFactory() {
return beanFactory;
}
}
Base entity for entities in the project:
public class BaseEntity {
private Date createDate;
private Date updateDate;
public BaseEntity() {
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public Date getUpdateDate() {
return updateDate;
}
public void setUpdateDate(Date updateDate) {
this.updateDate = updateDate;
}
}
and the Vote entity that I tried to delete:
#NodeEntity
public class Vote extends BaseEntity {
private static final String VOTED_ON = "VOTED_ON";
private final static String VOTED_FOR = "VOTED_FOR";
private static final String CREATED_BY = "CREATED_BY";
#GraphId
private Long id;
#RelatedTo(type = VOTED_FOR, direction = Direction.OUTGOING)
private Decision decision;
#RelatedTo(type = VOTED_ON, direction = Direction.OUTGOING)
private Criterion criterion;
#RelatedTo(type = CREATED_BY, direction = Direction.OUTGOING)
private User author;
private double weight;
private String description;
public Vote() {
}
public Vote(Decision decision, Criterion criterion, User author, double weight, String description) {
this.decision = decision;
this.criterion = criterion;
this.author = author;
this.weight = weight;
this.description = description;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Decision getDecision() {
return decision;
}
public void setDecision(Decision decision) {
this.decision = decision;
}
public Criterion getCriterion() {
return criterion;
}
public void setCriterion(Criterion criterion) {
this.criterion = criterion;
}
public User getAuthor() {
return author;
}
public void setAuthor(User author) {
this.author = author;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Vote vote = (Vote) o;
if (id == null)
return super.equals(o);
return id.equals(vote.id);
}
#Override
public int hashCode() {
return id != null ? id.hashCode() : super.hashCode();
}
#Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
Thanks to #MichaelHunger and Neo4j this issue has been fixed in Neo4j 2.2.2 and SDN 3.4.0.M1

How to use hibernate lucene search for entity which have many to one relation

I am using Hibernate lucene for searching. Now I want to search with an entity which has a many to one relation
I have two class one is catalogueBase and another one is Subject, here subject has a many-to-one relation (it is one sided relation)
catalogueBase.java class :
#Indexed
#JsonAutoDetect
#Entity
#Table(name="catalogueBase")
public class CatalogueBase extends BaseObject implements Serializable {
// some entities
// ...
private Subject subject;
// setter and get methods
// ...
#Field(index = Index.YES, analyze = Analyze.YES, store = Store.YES)
#ManyToOne
#NotFound(action= NotFoundAction.IGNORE)
#JoinColumn(name = "subject1", insertable = true, updatable=true, nullable = true)
#JsonProperty
public Subject getSubject() {
return subject;
}
public void setSubject(Subject subject) {
this.subject = subject;
}
}
Subject.java (what ever i want to search regarding subject it will be stored in description column) :
#Indexed
#JsonAutoDetect
#Entity
#Table(name="subject")
public class Subject implements java.io.Serializable {
private String description;
// ...
#Column(name = "subjectname", nullable = false, length = 150)
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
// ....
}
this is my DAO method :
private List<CatalogueBase> searchTitle(String queryString) throws InterruptedException {
Session session = getSession();
FullTextSession fullTextSession = Search.getFullTextSession(session);
fullTextSession.createIndexer().startAndWait();
org.hibernate.Query fullTextQuery = null;
List<CatalogueBase> resultList = null;
try{
QueryBuilder queryBuilder = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(CatalogueBase.class).get();
org.apache.lucene.search.Query luceneQuery = queryBuilder.keyword().onFields("title","subject").matching(queryString).createQuery();
fullTextQuery = fullTextSession.createFullTextQuery(luceneQuery, CatalogueBase.class);
List<CatalogueBase> contactList = fullTextQuery.list();
resultList = new ArrayList<CatalogueBase>();;
for (CatalogueBase catalogueBase : contactList) {
catalogueBase.setNoOfCopiesBooks(getCopydetailsCount(catalogueBase.getId()));
catalogueBase.setIssuedCount(getIssuedCount(catalogueBase.getId()));
resultList.add(catalogueBase);
}
} catch(Exception e) {
e.printStackTrace();
}
return resultList;
}
But it's giving an error like: SearchException: Unable to find field subject in com.easylib.elibrary.model.CatalogueBase
And I did something like this post, but error was the same.
I got solution.
I will just post code...
#Indexed // must
#JsonAutoDetect
#Entity
#Table(name="subject")
public class Subject implements java.io.Serializable {
private String description;
#ContainedIn // must
#Field(index = Index.YES, analyze = Analyze.YES, store = Store.YES)
#Column(name = "subjectname", nullable = false, length = 150)
public String getDescription() {
return this.description;
}
}
In catalogue:
#ManyToOne
#NotFound(action= NotFoundAction.IGNORE)
#JoinColumn(name = "subject1", insertable = true, updatable=true, nullable = true)
#JsonProperty
#IndexedEmbedded // must
public Subject getSubject() {
return subject;
}
public void setSubject(Subject subject) {
this.subject = subject;
}
And in the DAO, it must be:
org.apache.lucene.search.Query luceneQuery = queryBuilder.keyword().onFields("subject.description").matching(queryString).createQuery();