Lombok annotation Value. Cannot find method 'value' - spring

#Repository
#AllArgsConstructor
public class DataProvider {
#Value("${db.url}")
private String dbUrl;
}
IDE - idea
Plugin installed in IDE,dependecy installed

import # value from import org.springframework.beans.factory.annotation.Value;
it works

1- verifier your import, maybe you imported value from lombok, and it's wrong,so change your import:
import lombok.Value;
to:
import org.springframework.beans.factory.annotation.Value;

Related

MongoRepository Delete Method

Good afternoon fellow coders!
I have spent the last hour looking to delete a single document from my mongo "testCollection". I would like to make use of the MongoRepository delete / deleteAll methods. However, it does not remove the document. It persists regardless of how many times I run the test class method. No errors are reported and the user has readWrite permissions in the database. I am able to run the mongo command to remove the newly created test document.
I have read about using the mongo template and create it for the deletion to be performed. I'm happy to do that but I would rather keep it as simple as possible.
import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.MongoId;
#Data
#Document(collection = "testCollection")
public class TestClass {
#MongoId
private String id;
private String name;
public TestClass(String name) {
this.name = name;
}
}
Test Class Mongo Repository interface
import org.springframework.data.mongodb.repository.MongoRepository;
import java.util.List;
public interface TestClassRepository extends MongoRepository<TestClass, String> {
public List<TestClass> findAllByName(String name);
public void deleteAllByIdIn(List<TestClass> list);
}
Test Method
import org.junit.Assert;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
#RunWith(SpringRunner.class)
#TestPropertySource(value = {"classpath:application.properties"})
#AutoConfigureMockMvc
public class testClassTest {
#Autowired
private TestClassRepository testClassRepository;
#Test
public void crudTest() {
TestClass testObj = new TestClass("Test");
testClassRepository.save(testObj);
List<TestClass> testClassList = testClassRepository.findAllByName("Test");
Assert.assertEquals(1, testClassList.size());
TestClass test = testClassList.get(0);
testClassRepository.deleteAllByIdIn(testClassList);
// Fails this assertion: Found 1, expected 0.
Assert.assertEquals(0, testClassRepository.findAllByName("Test").size());
}
}
As anyone else experienced a similar issue? If so, how'd you go about resolving it?
Thanks!
Additions to original post:
Here is the mongo query generated by the MongoRepository. It appears that it is not actually adding the "remove" mongo command to the query. Query: { "name" : "Test"}, Fields: {}, Sort: {}
With a stroke of dumb luck I managed to figure out the issue. The problem was with the type of identifier annotation I was using. This explanation from another stackoverflow user (What is use of #MongoId in Spring Data MongoDB over #Id?) had me revisit this aspect of the model.
I switched the identifier annotation from #MongoId to #Id. Since I have both JPA and MongoDB annotations I needed to make sure I chose the one from the org.springframework.data.annotation package rather than the javax.persistance package.
Hope this explanation helps others!

In Spring boot application is #Component annotation optional for repo

I have created the basic application using Spring boot using JPA. I have added #AutoWired annotation for RatingRepo in RatingResource, but haven't added #Component annotation to RatingRepo
package com.example.demo;
import java.util.Arrays;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.RatingsRateService.model.Rating;
import com.example.demo.RatingsRateService.model.UserRating;
#RestController
#RequestMapping("ratingsdata")
public class RatingResource {
#Autowired
RatingRepo repo;
/*
* #RequestMapping("/{movieId}") public Rating
* getRating(#PathVariable("movieId") String movieId) { return new
* Rating(movieId,7); }
*/
#RequestMapping("users/{userid}")
public UserRating getRating(#PathVariable("userid") int userid) {
List<Rating> ratings =repo.findByUserId(userid);
/*
* List<Rating> ratings = Arrays.asList(new Rating("1",4), new Rating("2",3),
* new Rating("3",2));
*/
System.out.println(ratings);
UserRating userRating = new UserRating();
userRating.setUserRating(ratings);
return userRating;
}
}
package com.example.demo;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import com.example.demo.RatingsRateService.model.Rating;
//to update the data in database , created the interd=face and will implement
//class,primary key
public interface RatingRepo extends JpaRepository<Rating, Integer>{
#Query(" from Rating where userid = ?1")
List<Rating> findByUserId( int userid);
}
. Still, it is working fine. Can you someone please explain why it is so? Or it is not needed to add #Component annotation for the repo?
first of there is #Repository annotation required not #Component
and #Repository also auto configure due to below:
Probably you are using spring boot
Spring Data repositories usually extend from the Repository or CrudRepository interfaces. If you are using auto-configuration, repositories will be searched from the package containing your main configuration class (the one annotated with #EnableAutoConfiguration or #SpringBootApplication) down.
ref: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html#boot-features-spring-data-jpa-repositories

Spring Java Config DI defining and a ("concrete interface") of JpaRepository

I have the below code.
Note that I have an interface MySuperCoolEntityRepositoryContract.
And I have a "concrete interface" MySuperCoolEntityJpaRepository that implements my above MySuperCoolEntityRepositoryContract interface and JpaRepository.
All of that works fine with #ComponentScan.
I am changing my code to "java config", aka a centralized location where I can code up my DI definitions. (Also known as CompositionRoot in some circles).
The issue is when I try to "code up" the concrete for the interface. (Skip down to later in this question.
package com.me.domain.jpaentities;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Transient;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
#Entity(name = "MySuperCoolEntityTableName")
public class MySuperCoolEntity implements Serializable {
#Id
#Column(name = "CoolSurrogateKeyColumn")
private String coolSurrogateKey;
#Column(name = "CoolMagicValueColumn")
private String coolMagicValue;
public String getCoolSurrogateKey() {
return this.coolSurrogateKey;
}
public void setCoolSurrogateKey(String coolSurrogateKey) {
this.coolSurrogateKey = coolSurrogateKey;
}
public String getCoolMagicValue() {
return this.coolMagicValue;
}
public void setCoolMagicValue(String coolMagicValue) {
this.coolMagicValue = coolMagicValue;
}
}
===============
package com.me.dal.repositories.interfaces;
import com.me.domain.jpaentities.MySuperCoolEntity;
import java.util.Collection;
public interface MySuperCoolEntityRepositoryContract {
Collection<MySuperCoolEntity> findByCoolMagicValue(String coolMagicValue);
}
=========================
package com.me.dal.repositories;
import com.me.dal.repositories.interfaces.MySuperCoolEntityRepositoryContract;
import com.me.domain.jpaentities.MySuperCoolEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Collection;
#Repository
public interface MySuperCoolEntityJpaRepository extends MySuperCoolEntityRepositoryContract, JpaRepository<MySuperCoolEntity,String> {
Collection<MySuperCoolEntity> findByCoolMagicValue(String coolMagicValue);
}
Now this issue.
package com.me.myapplication.configuration;
import com.me.dal.repositories.MySuperCoolEntityJpaRepository;
import com.me.dal.repositories.interfaces.MySuperCoolEntityRepositoryContract;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class MyCompositionRoot {
#Bean
public MySuperCoolEntityRepositoryContract getAMySuperCoolEntityRepositoryContract()
{
return new MySuperCoolEntityJpaRepository(); /* << issue is here, this is an abstract class, aka, an interface with some methods defined */
}
}
Using the super cool JpaRepository "concrete interface" aka "really an abstract class but called an interface" aka "Interface Default Methods" ( see https://dzone.com/articles/interface-default-methods-java ) ........
The exact error is:
MySuperCoolEntityJpaRepository is abstract; cannot be instantiated
I do understand the error. MySuperCoolEntityJpaRepository is abstract. I get that.
But with this super cool "just extend JpaRepository and get all kinds of default functionality".....
How do I register a concrete JpaRepository with Spring DI (specifically with "code it up" java config ?
............
I tried making it a "class".
public class MySuperCoolEntityJpaRepository extends MySuperCoolEntityRepositoryContract, JpaRepository<MySuperCoolEntity,String>
but that wants me to define all those built in methods like "findAll",etc, etc.
Spring boot magically provides implementation for the methods defined in your interface. The #EnableJpaRepositories scans all packages below the package for interfaces extending JpaRepository and creates a Spring bean for it that is backed by an implementation of SimpleJpaRepository (spring data provides default imlpementations of CRUD repository through this class).
Your interface MySuperCoolEntityJpaRepository extends the interface MySuperCoolEntityRepositoryContract , but you only extend the JpaRepository on the interface MySuperCoolEntityJpaRepository which means spring will only provide the default implementations for methods in the interface MySuperCoolEntityJpaRepository . So try it like :
public interface MySuperCoolEntityRepositoryContract extends JpaRepository<MySuperCoolEntity,String>{
Collection<MySuperCoolEntity> findByCoolMagicValue(String coolMagicValue);
}
then extend this in your repository like :
#Repository
public interface MySuperCoolEntityJpaRepository extends MySuperCoolEntityRepositoryContract {
Collection<MySuperCoolEntity> findByCoolMagicValue(String coolMagicValue);
}
Related Post : how annotation #Repository in java spring work?
I figured out a workaround. I don't really like it, but I guess it works.
I also added MySuperCoolEntityBalServiceContract (you can get the idea from just the below), so you know why/how I need to have the getAMySuperCoolEntityRepositoryContract method in my CompositionRoot class below.
I'll leave this (not marked) as the answer in case someone else has a better way, or sees issue(s) with the below. I don't like the EntitiyManager work around, but it got things moving.
package com.me.myapplication.configuration;
import com.me.apicore.managers.MySuperCoolEntityBalService;
import com.me.apicore.managers.interfaces.MySuperCoolEntityBalServiceContract;
import com.me.dal.repositories.interfaces.MySuperCoolEntityRepositoryContract;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import javax.inject.Inject;
import javax.persistence.EntityManager;
#Configuration
public class MyCompositionRoot {
#Inject
private EntityManager entManager; /* part of the work around trick */
#Bean
public MySuperCoolEntityBalServiceContract getAMySuperCoolEntityBalServiceContract() {
return new MySuperCoolEntityBalService(this.getAMySuperCoolEntityRepositoryContract());
}
#Bean
public MySuperCoolEntityRepositoryContract getAMySuperCoolEntityRepositoryContract() {
//return new MySuperCoolEntityJpaRepository(); /* does not work. :( */
RepositoryFactorySupport factory = new JpaRepositoryFactory(entManager);
MySuperCoolEntityRepositoryContract repository = factory.getRepository(MySuperCoolEntityRepositoryContract.class);
return repository;
}
}
And I tweaked this (note the addition of the RepositoryDefinition annotation)
package com.me.dal.repositories.interfaces;
import com.me.domain.jpaentities.MySuperCoolEntity;
import org.springframework.data.repository.RepositoryDefinition;
import java.util.Collection;
#RepositoryDefinition(domainClass = MySuperCoolEntity.class, idClass = String.class)
public interface MySuperCoolEntityRepositoryContract {
Collection<MySuperCoolEntity> findByCoolMagicValue(String coolMagicValue);
}

Spring lombok #AllArgsConstructor is not working

I am using lombok but looks like #AllArgConstructor is not working when i'm create object of that class Sts is showing as
Description Resource Path Location Type
The constructor Employee(String, String, String[]) is undefined EmployeeController.java /spring-solr/src/main/java/com/ajay/solr/controller line 21 Java Problem
package com.ajay.solr.model;
import org.apache.solr.client.solrj.beans.Field;
import org.springframework.data.annotation.Id;
import org.springframework.data.solr.core.mapping.SolrDocument;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#AllArgsConstructor
#NoArgsConstructor
#SolrDocument(collection = "Employee")
public class Employee {
#Id
#Field
private int id;
#Field
private String name;
#Field
private String[] address;
}
And the class where I am using is
package com.ajay.solr.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
import com.ajay.solr.model.Employee;
import com.ajay.solr.repository.EmployeeRepository;
#RestController
public class EmployeeController {
#Autowired
private EmployeeRepository empRepository;
public void addEmployees() {
List<Employee> employees = new ArrayList<>();
employees.add(new Employee(373,"Sunil",new String[] {"Hyderabad","Gazipur"}));
employees.add(new Employee(374,"Ajay",new String[] {"AnjaiyahNagar","Maharajganj"}));
employees.add(new Employee(375,"Praveen",new String[] {"SRNagar","Baliya"}));
}
}
If you are using STS. You must have Lombok installed in your Eclipse by running lombok-xyz.jar
Please Try the Following the Steps:
1.Include pom in Maven .
2. Exit/Shutdown STS
3. Find lombok Jar from https://projectlombok.org/download
4.From Command Prompt/Shell java -jar lombok-1.x.y.jar
This will open a pop-up screen, then specify your path for STS/Eclipse.exe
Hit the install button
Start STS/Eclipse
(If you are still facing the issue, try updating your project: right-click on project -> Maven -> Update Project and the errors will disappear.)
annotationProcessor 'org.projectlombok:lombok'
compileOnly 'org.projectlombok:lombok'
Adding this in my build.gradle file, worked.

what is the idiomatic way to use ConfigurationProperties and EnableConfigurationProperties in tests?

i am trying to setup unit tests for some elements to be used within a spring(-boot) application, and i struggled with setup around ConfigurationProperties and EnableConfigurationProperties. the way i finally got it to work doesn't seem consistent with the examples that i have seen in that i have witnessed needing both ConfigurationProperties and EnableConfigurationProperties on my configuration class, which doesn't seem right, and i was hoping that someone might provide some guidance.
here is a simplified example:
JavaTestConfiguration.java
package com.kerz;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.validation.constraints.NotNull;
#Configuration
#ConfigurationProperties
#EnableConfigurationProperties
public class JavaTestConfiguration {
public void setFoo(String foo) {
this.foo = foo;
}
#NotNull
String foo;
#Bean
String foo() {
return foo;
}
}
JavaTestConfigurationTest.java
package com.kerz;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.assertEquals;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {JavaTestConfiguration.class})
#TestPropertySource("classpath:test.properties")
public class JavaTestConfigurationTest {
#Autowired
String foo;
#Test
public void shouldWork() throws Exception {
assertEquals("foo", "bar", foo);
}
}
test.properties
foo=bar
Your test is more integration test if you are starting Spring context. Therefore you should test also production spring configuration.
I would advise not to create testing configuration. Use one production configuration for testing.
You are also using #TestPropertySource annotation, which is used when you need to define test specific properties. If you can test with PROD configuration do not use it.

Resources