I am trying to create a Spring Boot CRUD application using Cassandra. I created a docker image and I already configured Cassandra, in CassandraConfiguration class but still is not creating my tables.
My CassandraConfiguration.java code:
#Configuration
#EnableCassandraRepositories
public class CassandraConfiguration extends AbstractCassandraConfiguration {
#Value("${env.values.cassandra.keyspace.name}")
private String keyspaceName;
.......................................
#Override
protected String getKeyspaceName() {
return keyspaceName;
}
#Override
protected int getPort() {
return contactPort;
}
#Override
protected String getContactPoints() {
return contactPoint;
}
#Override
public SchemaAction getSchemaAction() {
return SchemaAction.CREATE_IF_NOT_EXISTS;
}
#Override
protected List<CreateKeyspaceSpecification> getKeyspaceCreations() {
return List.of(
CreateKeyspaceSpecification.createKeyspace(keyspaceName)
.ifNotExists()
.withSimpleReplication(3));
}
#Bean
#Override
public CqlSessionFactoryBean cassandraSession() {
CqlSessionFactoryBean cassandraSession =
super.cassandraSession(); // super session should be called only once
cassandraSession.setUsername(username);
cassandraSession.setPassword(password);
return cassandraSession;
}
}
My entity:
#Table
#AllArgsConstructor
#NoArgsConstructor
#Builder
#EqualsAndHashCode(of = {"id"})
#Getter
#Setter
public class Account {
#PrimaryKey private String id = UUID.randomUUID().toString();
private String username;
private String email;
private String name;
private String password;
}
My pom.xml file:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-cassandra</artifactId>
</dependency>
After I've done quick check of the code and configuration you posted, nothing was obvious to me as being incorrect.
My suggestion is to review the application logs looking specifically for errors and warnings from the Cassandra Java driver. Chances are the Cassandra cluster is unreachable from your application usually because of some networking issue.
You will need to verify that there is network connectivity between your application and the contact points + CQL port you've configured. Cheers!
Related
I am trying to build a small app with Reactive jackson hibernate panache mysql as DB.
I am getting the below error.
"stackTrace": "java.lang.IllegalStateException: No pool has been
defined for persistence unit default-reactive\n\tat
io.quarkus.hibernate.reactive.runtime.FastBootHibernateReactivePersistenceProvider.registerVertxAndPool(FastBootHibernateReactivePersistenceProvider.java:233)\n\tat
io.quarkus.hibernate.reactive.runtime.FastBootHibernateReactivePersistenceProvider.rewireMetadataAndExtractServiceRegistry(FastBootHibernateReactivePersistenceProvider.java:180)\n\tat
io.quarkus.hibernate.reactive.runtime.FastBootHibernateReactivePersistenceProvider.getEntityManagerFactoryBuilderOrNull(FastBootHibernateReactivePersistenceProvider.java:156)\n\tat
io.quarkus.hibernate.reactive.runtime.FastBootHibernateReactivePersistenceProvider.createEntityManagerFactory(FastBootHibernateReactivePersistenceProvider.java:82)\n\tat
javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:80)\n\tat
javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)\n\tat
io.quarkus.hibernate.orm.runtime.JPAConfig$LazyPersistenceUnit.get(JPAConfig.java:118)\n\tat
io.quarkus.hibernate.orm.runtime.JPAConfig.startAll(JPAConfig.java:42)\n\tat
io.quarkus.hibernate.orm.runtime.JPAConfig_Subclass.startAll$$superaccessor5(JPAConfig_Subclass.zig:769)\n\tat
io.quarkus.hibernate.orm.runtime.JPAConfig_Subclass$$function$$5.apply(JPAConfig_Subclass$$function$$5.zig:29)\n\tat
io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:54)\n\tat
io.quarkus.arc.runtime.devconsole.InvocationInterceptor.proceed(InvocationInterceptor.java:62)\n\tat
io.quarkus.arc.runtime.devconsole.InvocationInterceptor.monitor(InvocationInterceptor.java:51)\n\tat
io.quarkus.arc.runtime.devconsole.InvocationInterceptor_Bean.intercept(InvocationInterceptor_Bean.zig:521)\n\tat
io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)\n\tat
io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41)\n\tat
io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32)\n\tat
io.quarkus.hibernate.orm.runtime.JPAConfig_Subclass.startAll(JPAConfig_Subclass.zig:727)\n\tat
io.quarkus.hibernate.orm.runtime.HibernateOrmRecorder.startAllPersistenceUnits(HibernateOrmRecorder.java:88)\n\tat
io.quarkus.deployment.steps.HibernateOrmProcessor$startPersistenceUnits951856026.deploy_0(HibernateOrmProcessor$startPersistenceUnits951856026.zig:74)\n\tat
io.quarkus.deployment.steps.HibernateOrmProcessor$startPersistenceUnits951856026.deploy(HibernateOrmProcessor$startPersistenceUnits951856026.zig:40)\n\tat
io.quarkus.runner.ApplicationImpl.doStart(ApplicationImpl.zig:751)\n\tat
io.quarkus.runtime.Application.start(Application.java:90)\n\tat
io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:100)\n\tat
io.quarkus.runtime.Quarkus.run(Quarkus.java:66)\n\tat
io.quarkus.runtime.Quarkus.run(Quarkus.java:42)\n\tat
io.quarkus.runtime.Quarkus.run(Quarkus.java:119)\n\tat
io.quarkus.runner.GeneratedMain.main(GeneratedMain.zig:29)\n\tat
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native
Method)\n\tat
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)\n\tat
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n\tat
java.base/java.lang.reflect.Method.invoke(Method.java:567)\n\tat
io.quarkus.runner.bootstrap.StartupActionImpl$3.run(StartupActionImpl.java:134)\n\tat
java.base/java.lang.Thread.run(Thread.java:831)\n"
Any idea What am missing?.
I have models
#Entity
public class Nation extends PanacheEntity {
#Column
public String country;
public Nation(String country, List<State> states) {
this.country = country;
this.states = states;
}
#OneToMany(cascade = {CascadeType.ALL})
public List<State> states = new ArrayList<>();
public Nation() {
}
}
#Entity
public class State extends PanacheEntity {
public State(String state, List<District> districts) {
this.state = state;
this.districts = districts;
}
#Column
public String state;
#OneToMany
public List<District> districts = new ArrayList<>();
public State() {
}
}
#Entity
public class District extends PanacheEntity {
public District(String district, List<Village> villages) {
this.district = district;
this.villages = villages;
}
#Column
public String district;
#OneToMany
public List<Village> villages = new ArrayList<>();
public District() {
}
}
#Entity
public class Village extends PanacheEntity {
#Column
public String village;
public Village(String village) {
this.village = village;
}
public Village() {
}
}
#Path("/nation")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#ApplicationScoped
public class NationResource {
#Inject
NationRepository nationRepository;
/* #Inject
public NationResource(NationRepository nationRepository) {
this.nationRepository = nationRepository;
}*/
#POST
#Path("save")
public Uni<Void> saveNation(Nation nation) {
return nationRepository.persist(nation);
}
#GET
public Uni<List<Nation>> getNations() {
return nationRepository.listAll();
}
#GET
#Path("{id}")
public Uni<Nation> getNation(#PathParam("id") Long id) {
return nationRepository.findById(id);
}
}
quarkus:
http:
port: 4754
log:
console:
json:
pretty-print: true
date-format: "YYYY-MM-dd HH:mm:ss"
exception-output-type: "detailed-and-formatted"
# configure your datasource
datasource:
db-kind: mysql
username: root
password: root
reactive:
url: vertx-reactive:mysql://localhost:3306/garrsolutions
# drop and create the database at startup (use `update` to only update the schema)
hibernate-orm:
database:
generation: drop-and-create
I resolved this problem by adding below snip into pom.xml dependencies:
<!-- JDBC driver dependencies -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-reactive-pg-client</artifactId>
</dependency>
In my case, i was trying to use H2 Db and i got the same problem. I resolved this problem using a map based approach like the exemple:
From:
quarkus.datasource.db-kind=h2
quarkus.datasource.jdbc.url=jdbc:h2:mem:guitars
quarkus.hibernate-orm.database.generation=drop-and-create
quarkus.hibernate-orm.packages=package br.com.mp.product.models
To:
quarkus.datasource."guitars".db-kind=h2
quarkus.datasource."guitars".jdbc.url=jdbc:h2:mem:guitars
quarkus.hibernate-orm."guitars".database.generation=drop-and-create
quarkus.hibernate-orm."guitars".packages=package br.com.mp.product.models
In this way the hibernate can find the specified class from map, but i didn't try with MySql Db like is your case.
I saw this example in this link: https://quarkus.io/guides/hibernate-orm
I am new to spring.
I just tried successfully using an entity class without #Id in Spring Data JDBC
Custom query was added in my repository for retrieving data from 2 mysql tables and returning an entity having the joined table data.
If I plan to use only custom queries, am I missing anything here?
Here's my entity class without #Id or #Entity:
public class Item
{
private long id;
private String code;
private String itemName;
private String groupName;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
}
Repository layer:
#Repository
public interface ItemRepository extends PagingAndSortingRepository<Item, Long>
{
#Query("SELECT a.id, a.code, a.name AS item_name,
b.name as group_name from item a, item_group b
WHERE a.group_id = b.id AND a.id=:id")
Item findItemById(#Param("id") Long id);
}
Service layer:
#Service
public class ItemServiceImpl implements ItemService
{
private final ItemRepository itemRepository;
public ItemServiceImpl(ItemRepository itemRepository)
{
this.itemRepository = itemRepository;
}
#Override
#Transactional(readOnly=true)
public Item findItemById(Long id)
{
return itemRepository.findItemById(id);
}
}
My updated main Configuration class in response to answer of Jens:
#SpringBootApplication
#EnableJdbcRepositories
public class SpringDataJdbcApplication extends AbstractJdbcConfiguration
{
public static void main(String[] args)
{
SpringApplication.run(SpringDataJdbcApplication.class, args);
}
#Bean
#ConfigurationProperties(prefix="spring.datasource")
public DataSource dataSource()
{
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
return dataSourceBuilder.build();
}
#Bean
NamedParameterJdbcOperations namedParameterJdbcOperations(DataSource dataSource)
{
return new NamedParameterJdbcTemplate(dataSource);
}
#Bean
PlatformTransactionManager transactionManager()
{
return new DataSourceTransactionManager(dataSource());
}
}
If you don't get any exceptions you should be fine. There shouldn't be anything in Spring Data JDBC that silently breaks when the id is not specified.
The problem is though: I don't consider it a feature that this works, but just accidental behaviour. This means it might break with any version, although replacing these methods with custom implementations based on a NamedParameterJdbcTemplate shouldn't be to hard, so the risk is limited.
The question though is: Why don't you add the #Id annotation, after all your entity does have an id. And the whole idea of a repository conceptually requires an id.
If it's working and you really don't want to use the annotations, you can do it. But I think that it's unnecessary complication. You can expect errors that would not be there if you had used the annotations and code will be harder to debug. If you are new in Spring I recommend to use annotations. But after all it depend on you how will you design your applications. For sure advantage of approach without annotations is higher control about database.
How to set up a PostgreSQL database connection in r2dbc Spring boot project?
I have tried the below configuration, it connects to the database but it's not returning any values
#Configuration
#EnableR2dbcRepositories
public class DatabaseConfig extends AbstractR2dbcConfiguration {
#Override
public ConnectionFactory connectionFactory() {
return ConnectionFactories.get("r2dbc:postgresql://localhost:5432/sample");
}
/*#Override
public ConnectionFactory connectionFactory() {
return ConnectionFactories.get(new PostgresqlConnectionFactory(
PostgresqlConnectionConfiguration.builder()
.host("localhost")
.port(5432)
.username("postgres")
.password("thirumal")
.database("sample")
.build()););
}*/
}
application.properties
spring.r2dbc.url=r2dbc:postgresql://localhost:5432/sample
spring.r2dbc.username=postgres
spring.r2dbc.password=thirumal
spring.r2dbc.pool.enabled=true
Model
#Data#NoArgsConstructor#AllArgsConstructor#Getter#Setter
#ToString
#Table("public.test")
public class Test implements Serializable{
/**
*
*/
private static final long serialVersionUID = 4205798689305488147L;
#Id//#Column("id")
private Long id;
private String name;
}
Repository
public interface TestRepository extends ReactiveCrudRepository<Test, Long> {
}
REST CONTROLLER:
#GetMapping("/test")
public Mono<Test> test() {
testRepository.findById(3L).subscribe(v->System.out.println("Value: " + v.toString()));
return testRepository.findById(3L);
}
It prints the output in the console but in the JSON, I get only empty braces {}
What is the correct way to configure? Any other configuration is required?
I found the problem. It's Lombok library, I didn't install it in eclipse.
When I created the getter and setter method manually it worked.
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
Then, I set up the lombok and used #getter and #setter and it worked.
This configuration works for me, but I use the DatabaseClient instead of the R2dbcRepositories to query the data:
#Configuration
public class DatabaseConfiguration extends AbstractR2dbcConfiguration {
#Override
#Bean
public ConnectionFactory connectionFactory() {
return new PostgresqlConnectionFactory(PostgresqlConnectionConfiguration.builder()
.host("localhost")
.port(5432)
.username("username")
.password("password")
.database("mydb")
.build());
}
}
Then in the repository:
#Repository
public class MyRepository {
#Autowired
private DatabaseClient client;
public Flux<String> getString() {
....
}
}
UPDATE:
If it's connect to the database probably your configuration is right, can you share also the code used to get the data?
It's possible that you are getting the result as Mono or Flux, but not reading from it (try with subscribe()).
Mono<String> mono = db.getData();
mono.subscribe(value -> System.out.println(value));
I have a SDR project and I am successfully validating the user entity for POST request but as soon as I update an existing entity using either PATCH or PUT the DB is updated BEFORE the validation is executed (the validator is being executed and error is returned but the DB is being updated anyway).
Do I need to setup a separate config for update ? Am I missing an extra step for that?
Entity
#Entity
#JsonIgnoreProperties(ignoreUnknown = true)
public class Member {
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "member_id_gen")
#SequenceGenerator(name = "member_id_gen", sequenceName = "member_id_seq")
#Id
#JsonIgnore
private long id;
#Version
private Integer version;
#NotNull
protected String firstName;
#NotNull
protected String lastName;
#Valid
protected String email;
}
Repository
#RepositoryRestResource(collectionResourceRel = "members", path = "member")
public interface MemberRepository extends PagingAndSortingRepository<Member, Long> {
public Member findByFirstName(String firstName);
public Member findByLastName(String lastName);
}
Validator
#Component
public class BeforeSaveMemberValidator implements Validator {
public BeforeSaveMemberValidator() {}
private String EMAIL_REGEX = "^[a-zA-Z0-9._%+-]+#[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}$";
#Override
public boolean supports(Class<?> clazz) {
return Member.class.equals(clazz);
}
#Override
public void validate(Object target, Errors errors) {
Member member = (Member) target;
if(ObjectUtils.isEmpty(member.getFirstName())) {
errors.rejectValue("firstName", "member.firstName.empty");
}
if(ObjectUtils.isEmpty(member.getLastName())) {
errors.rejectValue("lastName", "member.lastName.empty");
}
if(!ObjectUtils.isEmpty(member.getDni()) && !member.getDni().matches("^[a-zA-Z0-9]*$")) {
errors.rejectValue("dni", "member.dni.invalid");
}
if(!ObjectUtils.isEmpty(member.getEmail()) && !member.getEmail().matches(EMAIL_REGEX)) {
errors.rejectValue("email", "member.email.notValid");
}
}
}
BeforeSave service
#Service
#RepositoryEventHandler(Member.class)
public class MemberService {
#HandleBeforeCreate
#HandleBeforeSave
#Transactional
public void beforeCreate(Member member) {
...
}
}
I think you should rename your validator, for example, to MemberValidator then assign it as described here:
#Override
protected void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener v) {
v.addValidator("beforeCreate", new MemberValidator());
v.addValidator("beforeSave", new MemberValidator());
}
But I suggest you to use Bean validation instead of your custom validators. To use it in SDR project you can inject LocalValidatorFactoryBean, then assign it for 'beforeCreate' and 'beforeSave' events in configureValidatingRepositoryEventListener:
#Configuration
#RequiredArgsConstructor // Lombok annotation
public class RepoRestConfig extends RepositoryRestConfigurerAdapter {
#NonNull private final LocalValidatorFactoryBean validatorFactoryBean;
#Override
public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener v) {
v.addValidator("beforeCreate", validatorFactoryBean);
v.addValidator("beforeSave", validatorFactoryBean);
super.configureValidatingRepositoryEventListener(v);
}
}
In this case your SDR will automatically validate payloads of POST, PUT and PATCH requests for all exposed SDR repositories.
See my example for more details.
I tried the Spring Guide Accessing Data with MongoDB. What I can't figure out is how do I configure my code to not use the default server address and not use the default database. I have seen many ways to do it with XML but I am trying to stay with fully XML-less configurations.
Does anyone have an example that sets the server and database without XML and can be easily integrated into the sample they show in the Spring Guide?
Note: I did find how to set the collection (search for the phrase "Which collection will my documents be saved into " on this page.
Thank you!
p.s. same story with the Spring Guide for JPA -- how do you configure the db properties -- but that is another post :)
It would be something like this for a basic configuration :
#Configuration
#EnableMongoRepositories
public class MongoConfiguration extends AbstractMongoConfiguration {
#Override
protected String getDatabaseName() {
return "dataBaseName";
}
#Override
public Mongo mongo() throws Exception {
return new MongoClient("127.0.0.1", 27017);
}
#Override
protected String getMappingBasePackage() {
return "foo.bar.domain";
}
}
Example for a document :
#Document
public class Person {
#Id
private String id;
private String name;
public Person(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Example for a repository :
#Repository
public class PersonRepository {
#Autowired
MongoTemplate mongoTemplate;
public long countAllPersons() {
return mongoTemplate.count(null, Person.class);
}
}