Custom Queries are not working in ReactiveCosmosRepository - spring-data-jpa

I have created a cosmos repository by extending ReactiveCosmosRepository.
existing methods like findById, save are working fine for me.
At the same time added methods like findByColumnName(String name) are failing (Without throwing any exception).
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-cosmosdb-spring-boot-starter</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-spring-data-cosmos</artifactId>
<version>3.0.0-beta.2</version>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-cosmosdb</artifactId>
<version>2.6.11</version>
</dependency>
Any idea why this is happening?

According to your description, I tried this document to create a spring boot sample and also do it well. And I don't know how you created a method like "findByColumnName(String name)"; I think you can post your method in your question and it will be more straightforward.
From my research, Spring Data Azure Cosmos DB SDK 3.x.x supports #query annotation for defining custom queries! Maybe this document will help you.
Here's my code:
import java.util.List;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import com.azure.spring.data.cosmos.repository.Query;
import com.microsoft.azure.spring.data.cosmosdb.repository.CosmosRepository;
#Repository
public interface UserCosmosRepository extends CosmosRepository<User, String> {
#Query(value = "select * from c where c.firstName = #firstName")
List<User> findByFirstName(#Param("firstName") String firstName);
}
import java.util.List;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
#Service
public class TestService {
private static final Logger LOGGER = LoggerFactory.getLogger(TestService.class);
#Autowired
private UserRepository repository;
#Autowired
private UserCosmosRepository cosmosRepository;
public void run(String... var1) throws Exception {
repository.deleteAll().block();
final User testUser = new User("1", "Tasha", "Calderon", "4567 Main St Buffalo, NY 98052");
LOGGER.info("Saving user: {}", testUser);
// Save the User class to Azure CosmosDB database.
final Mono<User> saveUserMono = repository.save(testUser);
final Flux<User> firstNameUserFlux = repository.findByFirstName("testFirstName");
// Nothing happens until we subscribe to these Monos.
// findById will not return the user as user is not present.
final Mono<User> findByIdMono = repository.findById(testUser.getId());
final User findByIdUser = findByIdMono.block();
Assert.isNull(findByIdUser, "User must be null");
final User savedUser = saveUserMono.block();
Assert.state(savedUser != null, "Saved user must not be null");
Assert.state(savedUser.getFirstName().equals(testUser.getFirstName()), "Saved user first name doesn't match");
LOGGER.info("Saved user");
firstNameUserFlux.collectList().block();
final Optional<User> optionalUserResult = repository.findById(testUser.getId()).blockOptional();
Assert.isTrue(optionalUserResult.isPresent(), "Cannot find user.");
final User result = optionalUserResult.get();
Assert.state(result.getFirstName().equals(testUser.getFirstName()), "query result firstName doesn't match!");
Assert.state(result.getLastName().equals(testUser.getLastName()), "query result lastName doesn't match!");
LOGGER.info("Found user by findById : {}", result);
List<User> a = cosmosRepository.findByFirstName("Tasha");
if(a.size()>0) {
String id = a.get(0).getAddress();
LOGGER.info("Found user by name : {}", id);
}
}
}

Related

I'm doing simple integration of Mongodb and springboot, but unable to save data properly

I'm fairly new to java and spring boot. I'm trying to save data in mongo through spring, but it only saves _id=0 and model class.
My controller
package com.example.usermanagement.resource;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.example.usermanagement.model.User;
import com.example.usermanagement.repository.userRepository;
#RestController
public class UserController {
#Autowired
private userRepository repository;
#PostMapping("/saveUser")
public String saveUser(#RequestBody User user){
System.out.println(user);
repository.save(user);
return "User Added";
}
#GetMapping("/findAllUsers")
public List<User> getUsers(){
return repository.findAll();
}
#GetMapping("/findAllUsers{id}")
public Optional<User> getUser(#PathVariable int id){
return repository.findById(id);
}
#DeleteMapping("/delete/{id}")
public String deleteUser(#PathVariable int id){
repository.deleteById(id);
return "User Deleted";
}
}
On hitting save through postman, I get this in my db
[![enter image description here][1]][1]
My model
package com.example.usermanagement.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
#Getter
#Setter
#ToString
#Document(collection = "user_data")
public class User {
#Id
private int id;
private String firstName;
private String lastName;
}
And the repository
package com.example.usermanagement.repository;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import com.example.usermanagement.model.User;
#Repository
public interface userRepository extends MongoRepository<User, Integer> {
}
I do not understand what I'm doing wrong here, Why the rest of the data is not getting saved properly also Id is coming 0 rather than what I'm sending.
Post request I'm sending
{
"id":2,
"name":"yash",
"lastName":"asd",
"role":"dev"
}
When you dont use #Field to notify to database, you need to pass the same model class name as parameters.
{
"id":2,
"firstName":"yash",
"lastName":"asd"
}
Lombok won't automatically be configured. So you need to manually configure. Setting up lombok

how avoid to access to other data users. Spring boot + MongoDB

I'm developing a web application with Spring Boot and MongoDB. I'm following the MVC model.
I have a view which shows a list of stored data, but the app ignores the logged user and shows every objects.
https://i.stack.imgur.com/zl7TC.png
Here, the first row was added by another user, but it's showed anyway.
How could I get only the object allowed to the authenticated user?.
The only way I can see is checking the user Id after each query and get only the object of the given user. I think that there should be a better way to do this.
The code is the following:
Entity
import java.io.Serializable;
import java.util.Collection;
import java.util.Set;
import org.springframework.data.mongodb.core.index.IndexDirection;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document;
#Document(collection = "trackings")
public class Tracking extends Entity implements Serializable {
private static final long serialVersionUID = -1249902722123443448L;
#Indexed(unique = true, direction = IndexDirection.DESCENDING)
private String trackingName;
private String SoftwareName;
#DBRef
private Set<Alarm> alarms;
public String getTrackingName() {
return trackingName;
}
public void setTrackingName(String trackingName) {
this.trackingName = trackingName;
}
public String getSoftwareName() {
return SoftwareName;
}
public void setSoftwareName(String softwareName) {
SoftwareName = softwareName;
}
public Collection<Alarm> getAlarms() {
return alarms;
}
public void setAlarms(Set<Alarm> alarms) {
this.alarms = alarms;
}
}
Repository
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import us.etsii.fvt.domains.Tracking;
#Repository
public interface TrackingRepository extends MongoRepository<Tracking, String>{
Tracking findByTrackingName(String name);
}
Controller
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import us.etsii.fvt.domains.Alarm;
import us.etsii.fvt.domains.Tracking;
import us.etsii.fvt.domains.User;
import us.etsii.fvt.services.TrackingService;
import us.etsii.fvt.services.UserService;
#Controller
public class TrackingController {
#Autowired
private UserService userService;
#Autowired
private TrackingService trackingService;
#RequestMapping(value = { "/tracking" }, method = RequestMethod.GET)
public ModelAndView tracking() {
ModelAndView modelAndView = new ModelAndView();
// Añadimos el usuario al modelo
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
User user = userService.findUserByEmail(auth.getName());
modelAndView.addObject("currentUser", user);
modelAndView.addObject("fullName", user.getFullname());
// Añadimos la lista de trackings al modelo
List<Tracking> trackings = trackingService.findAll();
modelAndView.addObject("trackings", trackings);
// Devolvemos el modelo
modelAndView.setViewName("tracking");
return modelAndView;
}
...
}
Service
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import us.etsii.fvt.domains.Tracking;
import us.etsii.fvt.repositories.TrackingRepository;
#Service
public class TrackingService {
#Autowired
private TrackingRepository trackingRepository;
public Tracking findTrackingByName(String name) {
return trackingRepository.findByTrackingName(name);
}
public void saveTracking(Tracking tracking) {
trackingRepository.save(tracking);
}
public List<Tracking> findAll() {
return trackingRepository.findAll();
}
public Tracking findById(String id) {
Optional<Tracking> t = trackingRepository.findById(id);
if(!t.isPresent()) {
return null;
}
return t.get();
}
public void remove(String id) {
trackingRepository.deleteById(id);
}
}
There are ambiguous points in your question but assuming you have an User Entity:
You should get the logged in user from Spring Security
You should include a relation of User Entity to Tracking Entity (include User ID information in Tracking records)
Then you should query the mongo db Tracking Entity with the given user id.
You can use standard query by field functionality of Spring Repository.

JdbcTemplate object is null in my springboot application - using postgres

Here are my spring.datasource properties in application.properties-
spring.datasource.url=jdbc:postgresql://<hostname goes here>
spring.datasource.username=<username goes here>
spring.datasource.password=password
spring.datasource.driverClassName=org.postgresql.Driver
My main class is as follows:
#PropertySources(value = {#PropertySource("classpath:application.properties")})
#PropertySource(value = "classpath:sql.properties")
#SpringBootApplication
public class MyApp implements CommandLineRunner{
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
#Override
public void run(String... strings) throws Exception {
Execute execute = new Execute();
execute.executeCleanUp();
}
}
The Execute class is as follows:
import com.here.oat.repository.CleanUpEntries;
import com.here.oat.repository.CleanUpEntriesImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import java.io.IOException;
/***
*
*/
public class Execute {
#Autowired
private CleanUpEntries cleanUpEntries;
public void executeCleanUp() throws IOException {
cleanUpEntries = new CleanUpEntriesImpl();
cleanUpEntries.delete();
}
}
Here is the implementation class - CleanupEntriesImpl:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
#Component
public class CleanUpEntriesImpl implements CleanUpEntries{
#Autowired
private JdbcTemplate jdbcTemplate;
#Value(value = "${delete.query}")
private String deleteQuery;
#Override
public int delete() {
int id= jdbcTemplate.queryForObject(deleteQuery, Integer.class);
return id;
}
}
pom.xml has the following dependencies:
<!--jdbc driver-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1201-jdbc41</version>
<scope>runtime</scope>
</dependency>
Not sure why jdbcTemplate object is null when the delete() method is called. Any ideas?
The issue was resolved by removing all new operators from my classes and autowiring everything and making Execute a Component class.
Thanks!

No actions happened using htmlelements

currently i'm working on automated testing solution implementation. I decided to choose htmlelements but during this implementation i'm coding using clean webdriver+pagefactory to see the advantages of htmlelements. I'm not really good at coding and i got stuck at the almost beginning.
I've created java classes as was implemented in introduction on http://htmlelements.qatools.ru/.
Here is my code:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>w4w</groupId>
<artifactId>w4w</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>2.48.2</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ru.yandex.qatools.htmlelements</groupId>
<artifactId>htmlelements-java</artifactId>
<version>1.15</version>
</dependency>
<dependency>
<groupId>ru.yandex.qatools.ashot</groupId>
<artifactId>ashot</artifactId>
<version>1.4.12</version>
</dependency>
</dependencies>
</project>
LoginForm.java (Elements)
package htmlelements.Elements; /**
* Created by Asus on 06.12.2015.
*/
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import ru.yandex.qatools.htmlelements.annotations.Name;
import ru.yandex.qatools.htmlelements.element.Button;
import ru.yandex.qatools.htmlelements.element.HtmlElement;
import ru.yandex.qatools.htmlelements.element.TextInput;
#Name("Login Form")
public class LoginForm extends HtmlElement {
#Name("Username textbox")
#FindBy(id = "i_user")
private TextInput UserNameTextbox;
#Name("Password textbox")
#FindBy(id = "i_password")
private TextInput PasswordTextbox;
#Name("Login button")
#FindBy(xpath = "//*[#Value='Login']")
private Button LoginButton;
public void Login(String userName, String password){
UserNameTextbox.sendKeys(userName);
PasswordTextbox.sendKeys(password);
LoginButton.click();
}
}
LoginPage(PageObject):
package htmlelements.PageObjects;
import htmlelements.Elements.LoginForm;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import ru.yandex.qatools.htmlelements.annotations.Name;
import org.openqa.selenium.WebDriver;
import ru.yandex.qatools.htmlelements.element.TextInput;
import ru.yandex.qatools.htmlelements.loader.HtmlElementLoader;
/**
* Created by Asus on 06.12.2015.
*/
#Name("Login Page")
public class LoginPage {
private LoginForm loginForm;
public LoginPage(WebDriver driver){
HtmlElementLoader.populatePageObject(this, driver);
}
#FindBy(id = "i_user")
public TextInput usernm;
public void Login(String userName, String password){
loginForm.Login(userName, password);
}
}
MSWhtmlelements(test):
/**
* Created by Asus on 05.12.2015.
*/
import htmlelements.PageObjects.LoginPage;
import htmlelements.PageObjects.MainMenuPage;
import htmlelements.PageObjects.MerchantServiceWorkbenchScreen;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Test;
import java.util.concurrent.TimeUnit;
public class MSWhtmlelements {
private WebDriver driver;
#BeforeSuite
public void initDriver() throws Exception {
System.out.println("You are testing in firefox");
driver = new FirefoxDriver();
driver.manage().window().maximize();
}
#Test
public void trainingTest(){
driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
LoginPage loginPage = new LoginPage(driver);
MainMenuPage mainMenuPage = new MainMenuPage(driver);
MerchantServiceWorkbenchScreen mswScreen = new MerchantServiceWorkbenchScreen(driver);
String baseLink = "http://w4w-auto:41600/";
driver.get(baseLink);
loginPage.usernm.sendKeys("123123");
loginPage.Login("epichugin", "epichugin");
mainMenuPage.GoTo();
}
#AfterSuite
public void quitDriver() throws Exception {
driver.quit();
}
}
So, as you see i tried to invoke actions 2 times :
loginPage.usernm.sendKeys("123123"); - works fine
loginPage.Login("epichugin", "epichugin"); - doesn't work at all. Even no exceptions appear.
In case of webdriver+pageobjects it works very good and stable.
Here is my pageobject class which works. Test for this is almost the same:
/**
* Created by Asus on 04.12.2015.
*/
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class PageElements {
#FindBy(id = "i_user")
private WebElement UsernameTextbox;
#FindBy(id = "i_password")
private WebElement PasswordTextbox;
#FindBy(xpath = "//*[#Value='Login']")
private WebElement LoginButton;
public PageElements (WebDriver driver){
PageFactory.initElements(driver, this);
}
public void login (String username, String password){
UsernameTextbox.sendKeys(username);
PasswordTextbox.sendKeys(password);
LoginButton.click();
}
}
Thank you in advance!
You don't have #FindBy annotaion for your LoginForm class, how do you expect selenium would find your login form?

Exclude null properties from save operation

I'm using Spring Data for MongoDB -1.4.1.RELEASE and MongoDB 2.4.9
I'm using the mongoOperations.save() in order to update entities.
On previouse version, 1.2.0.RELEASE (due to a bug: DATAMONGO-571 ) I used to exclude some of the properties by setting their value to be null.
Now, This bug was fixed, and I'm not able to do so, but I still need to exclude some properties from the save operation (in case of update).
Does someone have an idea how this can be achieved?
I wrote abstract repository, that do partial update for single object. It expect that object contain 'id' field.
package xxx;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
import org.springframework.data.mongodb.repository.support.MongoRepositoryFactory;
import org.springframework.data.mongodb.repository.support.SimpleMongoRepository;
import java.io.Serializable;
import java.util.Map;
public abstract class ExtendedMongoRepository<T, ID extends Serializable> extends SimpleMongoRepository<T, ID> {
private Class<T> clazz;
//hidden constructor
private ExtendedMongoRepository(MongoEntityInformation metadata, MongoOperations mongoOperations) {
super(metadata, mongoOperations);
}
public ExtendedMongoRepository(MongoRepositoryFactory mongoRepositoryFactory, MongoOperations mongoOperations, Class<T> clazz) {
this(mongoRepositoryFactory.<T, ID>getEntityInformation(clazz), mongoOperations);
this.clazz = clazz;
}
protected Query getByIdQuery(ID id) {
return new Query(Criteria.where("_id").is(id));
}
/**
* Partial object update
* #param entity
* #param id
* #return
*/
public T updatePartial(T entity, ID id) {
ObjectMapper objectMapper = new ObjectMapper();
//exclude null
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
Map<String, Object> objectAsMap = objectMapper.convertValue(entity, Map.class);
//exclude id
objectAsMap.remove("id");
//add fields to update
Update u = new Update();
for (Map.Entry<String, Object> e : objectAsMap.entrySet()) {
u.set(e.getKey(), e.getValue());
}
getMongoOperations().updateFirst(getByIdQuery(id), u, clazz);
return getMongoOperations().findById(id, clazz);
}
}
And example how to use it.
public class GroupRepository extends ExtendedMongoRepository<Group, String> {
#Autowired
public GroupRepository(MongoRepositoryFactory mongoRepositoryFactory, MongoOperations mongoOperations) {
super(mongoRepositoryFactory, mongoOperations, Group.class);
}
}
MongoTemplate has dedicated methods to perform partial updates like:
updateFirst(…) - updates the first document matching a given criteria.
updateMulti(…) - updates all documents matching a given criteria.