Why can't i create a neo4j relationship with spring data for neo? - spring

i'm fairly new to spring data for neo (though i have experience with neo4j itself). i tried following the 'official' guide on spring data for neo, specifically the chapter on creating relationships.
But it seems i cannot get it to work. Spring is giving me an
java.lang.IllegalStateException: This index (Index[__rel_types__,Relationship]) has been marked as deleted in this transaction
Let me stress, that i am NOT removing any nodes or relationships. These are the relevant classes of my domain model:
#NodeEntity
public class User {
#GraphId
private Long nodeid;
#Indexed(unique = true)
private String uuid;
....
}
#NodeEntity
public class Website {
#GraphId
private Long nodeid;
#Indexed(unique = true)
private String uuid;
....
}
#RelationshipEntity(type = RelTypes.REL_USER_INTERESTED_IN)
public class UserInterest {
#GraphId
private Long nodeid;
#StartNode
private User user;
#EndNode
private Website site;
...
}
And this is my basic test which i can't get to turn green ..
(note that i omitted large portions of the code, the basic setup of the spring context etc. is working fine)
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
#Transactional
public class BaseTest {
#Autowired
protected Neo4jTemplate template;
#Autowired
protected GraphDatabaseService graphDatabaseService;
protected Transaction tx;
#Configuration
#EnableNeo4jRepositories
static class TestConfig extends Neo4jConfiguration {
TestConfig() throws ClassNotFoundException {
setBasePackage("me.bcfh.model");
}
#Bean
GraphDatabaseService graphDatabaseService() {
return new TestGraphDatabaseFactory().newImpermanentDatabase();
}
}
public void before() {
// provide implementation if necessary
}
public void after() {
// provide implementation if necessary
}
#Before
public void setup() throws Exception {
Neo4jHelper.cleanDb(graphDatabaseService, false);
before();
}
#After
public void tearDown() throws Exception {
after();
if (tx != null) {
tx.success();
tx.close();
tx = null;
}
}
}
public class BasicGraphTest extends BaseTest {
User user;
Website website;
UserInterest interest;
#Override
public void before() {
user = new User();
website = new Website();
website = template.save(website);
user = template.save(user);
}
#Test
#Transactional
public void dbShouldContainData() throws Exception {
UserInterest interest = new UserInterest();
interest.setSite(website);
interest.setUser(user);
template.save(interest);
// some assertions
...
}
}
The IllegalStateException is being thrown when I try persisting the UserInterest instance, which I do not understand because I am not removing anything anywhere.
The ways to create a relationship mentioned in the spring guide did not work for me either, here I got the same exception ..
Can anyone spot what I'm doing wrong here?
I am using Spring Version 4.1.4.RELEASE and Spring Data For Neo Version 3.2.1.RELEASE. Neo4j has version 2.1.6
Note: I also tried copying the domain model classes from the cineasts example into my project and borrowed a few lines of the DomainTest class but this too gives me the IllegalStateException, maybe there is something wrong with my setup?

I think you are getting your IllegalStateException because you are calling cleanDb in your setup method.
You may not need to clean the database. Since your tests are makred #Transactional anything you do in your tests gets rolled back at the end of the test.
Looks like the transaction is trying to rollback and can't find the relationship it expects.

Related

Why should I use #Service stereotype in Spring Boot?

I understand that #Service is a type of #Component just as #Controller and #Repository are. I also understand that these type-level (class level) stereotypes help component scan pick up different types in your spring project.
I noticed that a class I created FileResourceManager that handles business logic works just fine without #Service. I want to better understand what this stereotype does, and why it is useful. If it helps to explain #Component please do.
Here is an example class I was tempted to add #Service to because it prepares files from information gathered from a #Controller classes for a package irrelevant to spring that runs business logic
#Service
public class FileResourceManager {
private ConfigProp configProp;
#Autowired
private FormModel formModel;
public FileResourceManager(FormModel formModel) {
this.formModel = formModel;
}
public FormModel getformModel() {
return formModel;
}
public void init() throws IOException {
System.out.println("Initializing resources...");
clearDirectories();
writeTextboxToInputDirectories();
writeMultifileToInputDirectories();
}
private void clearDirectories() throws IOException {
configProp = configProp.getInstance();
RwUtils.clearDirectory(System.getProperty("user.dir")+configProp.getProperty("input.dir")+"input/");
RwUtils.clearDirectory(System.getProperty("user.dir")+configProp.getProperty("input.dir")+"file/");
}
private void writeMultifileToInputDirectories() throws IOException {
configProp = configProp.getInstance();
String inputDir = System.getProperty("user.dir")+configProp.getProperty("input.dir")+"input/";
String fileDir = System.getProperty("user.dir")+configProp.getProperty("input.dir")+"file/";
RwUtils.writeMultipartIntoFile(fileDir,formModel.getFile1());
RwUtils.writeMultipartIntoFile(fileDir,formModel.getFile2());
RwUtils.writeMultipartIntoFile(fileDir,formModel.getFile3());
for (MultipartFile record: formModel.getFiles4()) {
RwUtils.writeMultipartIntoFile(inputDir,record);
}
}
private void writeTextboxToInputDirectories() throws IOException {
configProp = configProp.getInstance();
String inputDir = System.getProperty("user.dir")+configProp.getProperty("input.dir")+"input/";
String fileDir = System.getProperty("user.dir")+configProp.getProperty("input.dir")+"file/";
if(formModel.getFile1File().isEmpty()) RwUtils.writeStringToFile(fileDir+"file1.txt",formModel.getFile1Text());
if(formModel.getFile2File().isEmpty()) RwUtils.writeStringToFile(fileDir+"file2.txt",formModel.getFile2Text());
if(formModel.getFile3File().isEmpty()) RwUtils.writeStringToFile(fileDir+"file3.txt",formModel.getFile3Text());
int i = 1;
String recordFileStr;
for (String record:formModel.getOldJsonText().split(";;;")) {
recordFileStr = inputDir+"textboxRecord"+i+".json";
RwUtils.writeStringToFile(recordFileStr,record);
i++;
}
}
// this class calls logic from a package that has no relation to spring-boot framework
public void runBusinessLogic() throws IOException, InvalidEntryException {
// logic
}
public void download(ZipOutputStream zippedOut) throws IOException {
ConfigProp configProp = ConfigProp.getInstance();
String downloadFormat = getformModel().getDownloadFormat();
FileSystemResource resource;
ZipEntry zipEntry;
File dir;
for (String dirStr:downloadFormat.split("-")) {
dir = new File(System.getProperty("user.dir")+configProp.getProperty("output.dir")+dirStr);
for (File file:dir.listFiles()) {
resource = new FileSystemResource(System.getProperty("user.dir")+configProp.getProperty("output.dir")+dirStr+"/"+file.getName());
zipEntry = new ZipEntry(file.getName());
// Configure the zip entry, the properties of the file
zipEntry.setSize(resource.contentLength());
zipEntry.setTime(System.currentTimeMillis());
// etc.
zippedOut.putNextEntry(zipEntry);
// And the content of the resource:
StreamUtils.copy(resource.getInputStream(), zippedOut);
zippedOut.closeEntry();
}
}
zippedOut.finish();
}
public static void main(String[] args) throws IOException {
// used to test runBusinessLogic() method
}
}
Here is an example service class where #Service seems significant
#Service
public class MyUserDetailsService implements UserDetailsService {
#Autowired
private MyUserRepository repo;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
MyUser user = repo.findByUsername(username);
if(user==null)
throw new UsernameNotFoundException("Username not found");
return new UserPrincipal(user);
}
public MyUser getUser(String username) throws UsernameNotFoundException {
MyUser user = repo.findByUsername(username);
if(user==null)
throw new UsernameNotFoundException("Username not found");
return user;
}
public MyUser createUser(MyUser user) {
String email = user.getEmail();
String username = user.getUsername();
if(repo.existsUserByEmail(email)) {
user = repo.findByEmail(email);
} else if(repo.existsUserByUsername(username)) {
user = repo.findByUsername(username);
} else {
this.repo.save(user);
user = repo.findByEmail(email);
}
return user;
}
}
If a java class is annotated with #Service , Spring will manage it and it can enjoy the benefits provided by Spring such as applying some AOP magics (such as those #Transactional , #Async , #PreAuthorize etc. stuff) to it. Also other instance can use #Autowired to access it rather than DIY (i.e. dependency injection idea). Think about that if your object is consisted of many dependencies which in turn consisted of many dependencies , configuring that instance to have a correct dependencies graph manually may not be an enjoyable thing to do. Not to mention the dependencies object should be come from the correct scope.
On the other hand, if a java class does not need any features provided by Spring , perhaps it is very simple or it is only be used by some class internally , you can keep it simple and simply create it by yourself such as :
ResourceManager = new FileResourceManager(formModel);
So it depends on if you need the spring features on a class. If you do not need it, you can keep it simple do not need to annotate #Service on it.

SpringBoot Junit testing for filters in Zuul

I'm new to Zuul J-unit testing. I have a couple of filters which is ChangeRequestEntityFilter and SessionFilter, Where I pasted my filtercode below. Can someone tell me how to write a Junit for the filter. I've searched and trying to use MockWire for the unit testing(Also I pasted my empty methods with basic annotations and WireMock port). I need at-least one proper example how this J-unit for Zuul works. I've referred the http://wiremock.org/docs/getting-started/ doc. Where I got what to do, but not how to do.
public class ChangeRequestEntityFilter extends ZuulFilter {
#Autowired
private UtilityHelperBean utilityHelperBean;
#Override
public boolean shouldFilter() {
// //avoid http GET request since it does'nt have any request body
return utilityHelperBean.isValidContentBody();
}
#Override
public int filterOrder() {
//given priority
}
#Override
public String filterType() {
// Pre
}
#Override
public Object run() {
RequestContext context = getCurrentContext();
try {
/** get values profile details from session */
Map<String, Object> profileMap = utilityHelperBean.getValuesFromSession(context,
CommonConstant.PROFILE.value());
if (profileMap != null) {
/** get new attributes need to add to the actual origin microservice request payload */
Map<String, Object> profileAttributeMap = utilityHelperBean.getProfileForRequest(context, profileMap);
/** add the new attributes in to the current request payload */
context.setRequest(new CustomHttpServletRequestWrapper(context.getRequest(), profileAttributeMap));
}
} catch (Exception ex) {
ReflectionUtils.rethrowRuntimeException(new IllegalStateException("ChangeRequestEntityFilter : ", ex));
}
return null;
}
}
I know ,I'm asking more. But give me any simple working complete example, I'm fine with it.
My current code with basic annotations and WireMock port.
#RunWith(SpringRunner.class)
#SpringBootTest
#DirtiesContext
#EnableZuulProxy
public class ChangeRequestEntityFilterTest {
#Rule
public WireMockRule wireMockRule = new WireMockRule(8080);
#Mock
ChangeRequestEntityFilter requestEntityFilter;
int port = wireMockRule.port();
#Test
public void changeRequestTest() {
}
}
Have you tried #MockBean?
https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/mock/mockito/MockBean.html
"When #MockBean is used on a field, as well as being registered in the application context, the mock will also be injected into the field. Typical usage might be:"
#RunWith(SpringRunner.class)
public class ExampleTests {
#MockBean
private ExampleService service;
#Autowired
private UserOfService userOfService;
#Test
public void testUserOfService() {
given(this.service.greet()).willReturn("Hello");
String actual = this.userOfService.makeUse();
assertEquals("Was: Hello", actual);
}
#Configuration
#Import(UserOfService.class) // A #Component injected with ExampleService
static class Config {
}
}
Here there is another approach:
private ZuulPostFilter zuulPostFilter;
#Mock
private anotherService anotherService;
#Mock
private HttpServletRequest request;
#Before
public void before() {
MockitoAnnotations.initMocks(this);
MonitoringHelper.initMocks();
zuulPostFilter = new ZuulPostFilter(anotherService);
doNothing().when(anotherService).saveInformation(null, false);
}
#Test
public void postFilterTest() {
log.info("postFilterTest");
RequestContext context = new RequestContext();
context.setResponseDataStream(new ByteArrayInputStream("Test Stream".getBytes()));
context.setResponseGZipped(false);
RequestContext.testSetCurrentContext(context);
when(request.getScheme()).thenReturn("HTTP");
RequestContext.getCurrentContext().setRequest(request);
ZuulFilterResult result = zuulPostFilter.runFilter();
assertEquals(ExecutionStatus.SUCCESS, result.getStatus());
assertEquals("post", zuulPostFilter.filterType());
assertEquals(10, zuulPostFilter.filterOrder());
}
In this case you can test the filter and mock the services inside it without having to autowire it, the problem with the #autowired is that if you have services inside the filter, then it is going to be an integration test that is going to be more difficult to implement.

Spring Casheable returned cached objects fail equality check

The issue I am facing is that two objects returned from spring cacheable method with a same key fail assertSame test. Why are these objects not sharing one same storage area?
Details:
I am using redis cache mechanism to implement caching in a spring boot REST api.
The caching works correctly in the way that it first retrieve the data from externally provided source (JPS repository accessing a database) and then subsequent calls for the same cache key returns data from cache. However, I am not able to mimic this behavior completely in the JUnit test cases. My assertEquals or assertSame fail on 2 objects returned from the cache.
my code base looks as below:
mvn dependencies:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.7.6.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
Spring application config:
#SpringBootApplication
#EnableCaching
public class Application {
#Value("${redis.host}")
private String redisHost;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory jedisConFactory = new JedisConnectionFactory();
jedisConFactory.setHostName(redisHost);
jedisConFactory.setPort(6379);
return jedisConFactory;
}
#Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(jedisConnectionFactory());
return template;
}
#Bean
CacheManager cacheManager() {
return new RedisCacheManager(redisTemplate());
}
Service Class:
#Service
public class CIDomainService {
private RedisTemplate<String, Object> redisTemplate;
private CIDomainDAO ciDomainDAO;
#Autowired
public CIDomainService(CIDomainDAO ciDomainDAO, RedisTemplate<String, Object> redisTemplate) {
this.ciDomainDAO = ciDomainDAO;
this.redisTemplate = redisTemplate;
}
#Cacheable(value = "ciDomain", key = "#id")
public CIDomain getCIDomain(int id) {
CIDomain ciDomain = new CIDomain();
ciDomain.setId(id);
ciDomain.setName("SomeName");
return ciDomain;
}
public void clearAllCache() {
redisTemplate.delete("listCIDomains");
redisTemplate.delete("ciDomain");
}
}
ciDomainDAO in the service above is just a JPS repository interface using the findAll() method to retrieve data from external database or in-memory database. My Test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles("local")
#SpringBootTest
public class CIDomainServiceIntegrationTest {
#Autowired
CIDomainService ciDomainServiceSpy;
#Before
public void setUp(){
ciDomainServiceSpy.clearAllCache();
}
#Test
public void listCIDomains_ShouldRetrieveCIDomainsWithCachingPluggedIn() {
CIDomain domain1 = ciDomainServiceSpy.getCIDomain(1);
CIDomain domain2 = ciDomainServiceSpy.getCIDomain(2);
CIDomain domain3 = ciDomainServiceSpy.getCIDomain(1);
assertSame(domain1, domain3); //fails
}
My Domain Class:
#Entity
#Table(name = "CI_DOMAIN")
public class CIDomain implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Column(name = "name")
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
based on this post I understand that object is retrieved from the repository for the very first call and then later call will fetch this object from cache provided same "key" is provided. I am doing the same thing in my test case above but assertSame is failing. Spring cacheable must be caching object in memory which is fetched for a given request. Why would it send different objects everytime for the same requested key.
I have tried to have an alternative solution where I used spy on the service class and verify method calls based on a same key request. However, I encountered different issues in doing that. Creating a spy on the service class does not even use caching mechanism and it does call service getCIDomain method even if same key is provided. I followed this, this, this, this, this and lots of other posts for further analysis but could not get it working either through assertSame of spy.
Any help would really be appreciated.
I had got this issue resolved and was able to design the test case as it should be for verifying spring cacheable mechanism.
Just providing my analysis and resolution below to help someone out there facing this same issue.
I mentioned in my comments and original questions above that assertSame would not work due to how serialization works and assertEquals though was working but it was kind of not satisfying my test requirement.
The conclusion I made (based on comments) that I should actually test number of method calls and not the result. I tried to mock the CIDomainDAO repository dao as in my question but I faced with couple issues. Creating mocked object of CIDomainDAO and passing it in the CIDomainService constructor was not triggering spring cache and my test was failing. If I do not mock CIDomainDAO and tried spying on CIDomainService to check no of method calls and ran my test then I was ending up getting
org.mockito.exceptions.misusing.UnfinishedVerificationException: Missing
method call for verify(mock).
This was obvious as mocking does not seem to work on final methods that CIDomainDAO might have had in its spring generated JPARepository implementation.
This post helped me understand this behavior of mockito.
Concluding that I need to mock CIDomainDAO somehow, I ended up injecting mocked version of CIDomainDAO respository in CIDomainService class. I had to define a CIDomainDAO setter in CIDomainService class specially for this purpose. After that I tried no of method calls and it worked as expected i.e., service called two times but CIDomainDAO called once as the data was returned from the cache in the second call.
Provided below the modified classes from my original question above.
The service class:
#Service
public class CIDomainService {
private RedisTemplate<String, Object> redisTemplate;
private CIDomainDAO ciDomainDAO;
#Autowired
public CIDomainService(CIDomainDAO ciDomainDAO, RedisTemplate<String,
Object> redisTemplate) {
this.ciDomainDAO = ciDomainDAO;
this.redisTemplate = redisTemplate;
}
#Cacheable(value = "ciDomain", key = "#id")
public CIDomain getCIDomain(int id) {
CIDomain ciDomain = new CIDomain();
ciDomain.setId(id);
ciDomain.setName("SomeName");
return ciDomain;
}
public void clearAllCache() {
redisTemplate.delete("listCIDomains");
redisTemplate.delete("ciDomain");
}
public void setCIDomainDAO(CIDomainDAO ciDomainDAO ) {
this.ciDomainDAO = ciDomainDAO;
}
}
And this is the updated test case:
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles("local")
#SpringBootTest
public class CIDomainServiceIntegrationTest {
#Autowired
#InjectMocks
CIDomainService ciDomainService;
#Mock
CIDomainDAO ciDomainDAO;
#Before
public void setUp() {
Mockito.reset(ciDomainDAO);
ciDomainService.clearAllCache();
}
#Test
public void listCIDomains_ShouldNotAttemptToCallRepositoryWhenCachingEnabledAfterFirstCallOfRetrievingCIDomains() {
List<CIDomain> domains1 = ciDomainService.listCIDomains();
List<CIDomain> domains2 = ciDomainService.listCIDomains();
Mockito.verify(ciDomainDAO, Mockito.times(1)).findAll();
}
#Test
public void listCIDomains_ShouldAttemptToCallRepositoryWhenCachingIsClearedAfterFirstCallOfRetrievingCIDomains() {
List<CIDomain> domains1 = ciDomainService.listCIDomains();
ciDomainService.clearAllCache();
List<CIDomain> domains2 = ciDomainService.listCIDomains();
Mockito.verify(ciDomainDAO, Mockito.times(2)).findAll();
}
#After
public void postSetUp() {
Mockito.validateMockitoUsage();
ciDomainService.clearAllCache();
Mockito.reset(ciDomainDAO);
}
}

Entity can still be found after being deleted

I'm working with Spring Data Neo4j 4 and have the following user entity
#NodeEntity
public class User{
private Long id;
private String username;
//Getter, Setter
}
Using the Neo4j GraphRepository, i first create the user in one transaction and later delete him in a second transaction.
Working with the standalone Neo4j server on localhost:7474 i get no result when running "MATCH (n) return n" but when i run the findOne(Long id) method of the GraphRepository using the id of the User i just deleted, i get the user, i just deleted returned.
Is there some kind of behavior involved i don't understand?
Regards
Urr4
Edit:
My application class
#SpringBootApplication(scanBasePackages = {/.../})
#EnableNeo4jRepositories(basePackages = {/.../})
#EnableTransactionManagement
public class MyApplication extends Neo4jConfiguration {
public static void main(String[] args) {
SpringApplication.run(TSApplication.class, args);
}
#Override
#Bean
public Neo4jServer neo4jServer() {
return new RemoteServer(/.../);
}
#Override
#Bean
public SessionFactory getSessionFactory() {
return new SessionFactory("/.../);
}
}
After Michaels comment, i've googled a bit and added the following to my Controller:
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = RuntimeException.class)
Afterwards it worked - Thank you all :)

PlayFramework: Depedencies are not inject using Spring and got NullPointerException

When i try to integrate Spring-Dependency-Injection in Play-framework with Java 8. In controller the dependencies are not injected. I am using spring stereo-type annotations. Get
Follwowing is my code:
Configuration:
public class GlobalConfiguration extends GlobalSettings{
private AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
#Override
public void onStart(Application app) {
super.onStart(app);
// AnnotationConfigApplicationContext can only be refreshed once, but we do it here even though this method
// can be called multiple times. The reason for doing during startup is so that the Play configuration is
// entirely available to this application context.
applicationContext.scan("com.harmeetsingh13.controllers", "com.harmeetsingh13.service.impl", "com.harmeetsingh13.dao.impl");
applicationContext.refresh();
// This will construct the beans and call any construction lifecycle methods e.g. #PostConstruct
applicationContext.start();
}
#Override
public void onStop(Application app) {
// This will call any destruction lifecycle methods and then release the beans e.g. #PreDestroy
applicationContext.close();
super.onStop(app);
}
#Override
public <A> A getControllerInstance(Class<A> clazz) throws Exception {
return applicationContext.getBean(clazz);
}
}
Controller:
#Component
public class UserController extends Controller{
#Autowired
private UserService userService;
public Result findUserById(Integer userId) {
Optional<User> user = userService.findUserById(userId);
if(user.isPresent()){
}
return null;
}
}
Service:
#Service
public class UserServiceImpl implements UserService {
#Autowired
private UserDao userDao;
#Override
public Optional<User> findUserById(int id) {
List<User> users = userDao.getAllUsers();
return users.stream().filter(user -> user.id == id).findFirst();
}
}
This is the link where i found sample application
This is really my stupid mistake. In play-framework we always need to put the custom global configuration file in project app folder at root and play-framework always find to search Global file name at app folder root and load into the memory. In my case, my GlobalConfiguration file are not loaded in the memory and default configuration are used by play-framework. For Global-Settings click on this link for more information

Resources