Java 8 Optional.ofNullable.map producing Non static method reference error - java

I have a method to verify a recipient of an email.
In my code .map(Recipient::getId) produces the error :
Non static method cannot be reference from a static context.
private Long verifyRecipient(Long recipientId) throws NotFoundException {
return Optional.ofNullable(recipientRepository.findById(recipientId))
.map(Recipient::getId)
.orElseThrow(()-> new NotFoundException("recipient with ID" + recipientId +
" was not found"));
}
Recipient class:
#Entity
public class Recipient {
#Id
#GeneratedValue
private Long id;
#NotBlank
private String name;
#NotBlank
#Email
#Column(unique = true)
private String emailAddress;
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;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
}
I am using SpringBoot and H2 in memory database.
So I also have a RecipientRepository interface:
public interface RecipientRepository extends JpaRepository<Recipient, Long> {}
Defination of the findById() method:
Optional<T> findById(ID var1);

The method findById() already returns an Optional<T>, so you don't need to wrap the result with additional Optional.ofNullable() in this situation.
Actually, the line:
Optional.ofNullable(recipientRepository.findById(recipientId));
returns Optional<Optional<Recipient>>, which is redundant.
Instead, you can just write:
private Long verifyRecipient(Long recipientId) throws NotFoundException {
return recipientRepository.findById(recipientId)
.map(Recipient::getId)
.orElseThrow(() ->
new NotFoundException("Recipient with ID " + recipientId + " was not found"));
}

Related

How to update one field in my Entity using JPA Repository

I have Entity with 3 fields: id, lastname and phoneNumber. I want to create method which works for update all fields or only one or two.
I use Hibernate and JPA Repository.
When I try to update all fields everything works well but when for example i want to update only lastname without changing of phoneNumber I have in output null insted of old phoneNumber.
Here is my method from Controller:
#PutMapping("/students/update/{id}")
public String updateStudentById(#ModelAttribute Student student, #ModelAttribute StudentDetails studentDetails,
String lastname, String phoneNumber,
#PathVariable Long id) {
Optional<Student> resultOptional = studentRepository.findById(id);
//Student result =resultOptional.get();
resultOptional.ifPresent((Student result) -> {
result.getStudentDetails().setPhoneNumber(studentDetails.getPhoneNumber()); result.getStudentDetails().setLastname(studentDetails.getLastname());
studentRepository.save(result);
});
return "Student updated";
}
The class for update:
#DynamicUpdate
#Entity
public class StudentDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="lastname")
private String lastname;
#Column(name="phone_number")
private String phoneNumber;
public StudentDetails() {
}
public StudentDetails(Long id, String lastname, String phoneNumber) {
this.id = id;
this.lastname = lastname;
this.phoneNumber = phoneNumber;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
The class which has relation with StudentDetails:
#Entity
#Table(name = "student")
#DynamicUpdate
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
private String name;
#Column(name = "email")
private String email;
//#OneToMany(mappedBy = "student")
#ManyToMany
#JoinTable(name="course_student",joinColumns = #JoinColumn(name="student_id"),
inverseJoinColumns = #JoinColumn(name="course_id"))
private List<Courses> courses;
#OneToOne(cascade = CascadeType.ALL)
// #JoinColumn(name="studen/_details_id") // with this we have dobule student_details column
private StudentDetails studentDetails;
public List<Courses> getCourses() {
return courses;
}
public void setCourses(List<Courses> courses) {
this.courses = courses;
}
public StudentDetails getStudentDetails() {
return studentDetails;
}
public void setStudentDetails(StudentDetails studentDetails) {
this.studentDetails = studentDetails;
}
// Methods for StudentViewController
public String getLastname(){
return studentDetails.getLastname();
}
public String getPhoneNumber(){
return studentDetails.getPhoneNumber();
}
public Student() {
}
public Student(String name, String email, StudentDetails studentDetails) {
// this.id = id;
this.name = name;
this.email = email;
this.studentDetails = studentDetails;
}
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;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
'}';
}
}
I was looking for solution and I added #DynamicUpdate but still it doesn't work.
Your code works properly. When you only provide lastName parameter in your request, then the phoneNumber parameter will be mapped to null so you override the phoneNumer property in your entity with this null value.
Change the code in the following way:
resultOptional.ifPresent((Student result) -> {
if(studentDetails.getPhoneNumber()!=null) {
result.getStudentDetails().setPhoneNumber(studentDetails.getPhoneNumber());
}
if(studentDetails.getLastname()!=null) {
result.getStudentDetails().setLastname(studentDetails.getLastname());
}
studentRepository.save(result);
});
Unfortunately it raises an other problem: How will you delete these fields? (How can you set them explicitly to null? )
A possible solution if you check for the "" (empty string) and set the property to null if the parameter is empty string.
It will be a quite messy code anyway...
You should consider using the Spring Data Rest package. It automatically creates all of the standard REST endpoints for your entities and handles all of these PUT/PATCH/POST/DELETE issues out of the box.
why don't you just set the params of your request in you setters?
resultOptional.ifPresent((Student result) -> {
result.getStudentDetails().setPhoneNumber(phoneNumber);
result.getStudentDetails().setLastname(lastname);
studentRepository.save(result);
});
You forget set #OneToOne mapping in StudentDetails - StudentDetails also need field of type Student which will be annotated #OneToOne.
Also you have to ensure, that all of entity fields will be filled - read more about fetch types.

when the Get request is other than Id getting this exception :Failed to convert value of type java.lang.String to required type java.lang.Long

In my SpringBoot code When i make use of Get request for user/{id} is working fine but when use of the request user/modelname.
I'm getting the exception:
Failed to convert value of type 'java.lang.String' to required type
'java.lang.Long';
carController.java
#GetMapping("/user/{id}")
public Car getUser(#PathVariable Long id) {
return carRepository.findOne(id);
}
#GetMapping("/user/modelname")
public List<Car> searchUserByModel(#RequestBody String modelname) {
return carRepository.findByModelname(modelname);
}
carRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
public interface CarRepository extends JpaRepository<Car, Long>{
public List<Car> findByModelname(String modelname);
}
car.java
#Entity
public class Car {
#Id
#GeneratedValue
private Long id;
private String modelname;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getModelname() {
return modelname;
}
public void setModelname(String modelname) {
this.modelname = modelname;
}
public Car(Long id,String modelname) {
this.id=id;
this.modelname = modelname;
}
#Override
public String toString() {
return "Car [id=" + id + ", modelname=" + modelname +"]";
}
public Car() {
}
}
Your request is not reaching to #GetMapping("/user/modelname"). it is always going to #GetMapping("/user/{id}") only because it satisfied the condition.
Try changing the url to something else like this #GetMapping("/users/modelname") and check ,it will hit definitely.

Cannot delete an entity using morphia (mongodb)

I keep getting the same error whenever I try to delete an entity using Morphia:
org.mongodb.morphia.query.ValidationException: The field '_id' could not be found in ...
while validating - _id; if you wish to continue please disable validation.
I don't really want to disable validation. I just want to delete the object.
Here is my delete method of the service I'm writing:
public void delete(ObjectId id) {
BaseMaterial baseMaterial = this.findOne(id);
WriteResult writeResult = this.repo.delete(baseMaterial);
}
and here is the findOne method in the same service (i.e. this.findOne)
public BaseMaterial findOne(ObjectId id) {
Query<BaseMaterial> query = repo.createQuery(BaseMaterial.class);
return Optional.ofNullable(query.field("id").equal(id).get())
.orElseThrow(() -> new DataRetrievalFailureException(
"Failed to fetch " + this.getClass().getName() + " with id " + id.toString()));
}
And here is my POJO:
#Entity("baseMaterial")
public class BaseMaterial {
#Id
#NotNull
protected ObjectId id;
#NotEmpty
private String name;
private String description;
public String get_id() {
return this.id.toString();
}
#JsonIgnore
public ObjectId getId() {
return id;
}
public void setId(ObjectId id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
The findOne method of shown above works as expected so I really have no idea why this is happening.
Any ideas?
I don't see a field annotated with #Id...

Dropwizard/Jersey is giving "Unable to process JSON" message on GET request

I'm trying to make my first simple project with Dropwizard. I have a MySQL-database, and the idea is to get the data (companies) from there and represent it as JSON. I have followed the Getting started page by Dropwizard and this tutorial to get connected to database with Hibernate.
The idea is that URL "/companies" serves all the companies as JSON, and it is working fine.
URL "/companies/{id}" is supposed to give a single company with given id, but every request gives code 400 and message "Unable to process JSON". The details field in the response says
"No serializer found for class
jersey.repackaged.com.google.common.base.Present and no properties
discovered to create BeanSerializer (to avoid exception, disable
SerializationFeature.FAIL_ON_EMPTY_BEANS) )"
If I give an id of company that does not exist in database, the class in mentioned message changes to
jersey.repackaged.com.google.common.base.Absent
The company class is here:
public class Company {
#ApiModelProperty(required = true)
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "name")
private String name;
#Column(name = "address")
private String address;
#Column(name = "zipcode")
private String zipCode;
#Column(name = "email")
private String eMail;
#Column(name = "mobile")
private String mobile;
public Company() {
}
public Company (String name, String address, String zipCode, String eMail, String mobile) {
this.name = name;
this.address = address;
this.zipCode = zipCode;
this.eMail = eMail;
this.mobile = mobile;
}
#JsonProperty
public long getId() {
return id;
}
#JsonProperty
public void setId(long id) {
this.id = id;
}
#JsonProperty
public String getName() {
return name;
}
#JsonProperty
public void setName(String name) {
this.name = name;
}
#JsonProperty
public String getAddress() {
return address;
}
#JsonProperty
public void setAddress(String address) {
this.address = address;
}
#JsonProperty
public String getZipCode() {
return zipCode;
}
#JsonProperty
public void setZipCode(String zipCode) {
this.zipCode = zipCode;
}
#JsonProperty
public String geteMail() {
return eMail;
}
#JsonProperty
public void seteMail(String eMail) {
this.eMail = eMail;
}
#JsonProperty
public String getMobile() {
return mobile;
}
#JsonProperty
public void setMobile(String mobile) {
this.mobile = mobile;
}
}
DAO is here:
public class CompanyDAO extends AbstractDAO<Company> {
public CompanyDAO(SessionFactory sessionFactory) {
super(sessionFactory);
}
public List<Company> findAll() {
return list(namedQuery("com.webapp.project.core.Company.findAll"));
}
public Optional<Company> findById(long id) {
return Optional.fromNullable(get(id));
}
}
Application class:
public class HelloWorldApplication extends Application<HelloWorldConfiguration> {
public static void main(String[] args) throws Exception {
new HelloWorldApplication().run(args);
}
#Override
public String getName() {
return "hello-world";
}
/**
* Hibernate bundle.
*/
private final HibernateBundle<HelloWorldConfiguration> hibernateBundle
= new HibernateBundle<HelloWorldConfiguration>(
Company.class
) {
#Override
public DataSourceFactory getDataSourceFactory(
HelloWorldConfiguration configuration
) {
return configuration.getDataSourceFactory();
}
};
#Override
public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {
bootstrap.addBundle(new SwaggerBundle<HelloWorldConfiguration>() {
#Override
protected SwaggerBundleConfiguration getSwaggerBundleConfiguration(HelloWorldConfiguration sampleConfiguration) {
return sampleConfiguration.getSwaggerBundleConfiguration();
}
});
bootstrap.addBundle(hibernateBundle);
}
#Override
public void run(HelloWorldConfiguration configuration,
Environment environment) {
final CompanyDAO companyDAO = new CompanyDAO(hibernateBundle.getSessionFactory());
environment.jersey().register(new CompaniesResource(companyDAO));
environment.jersey().register(new JsonProcessingExceptionMapper(true));
}
}
Configuration class:
public class HelloWorldConfiguration extends Configuration {
#Valid
#NotNull
private DataSourceFactory database = new DataSourceFactory();
#NotNull
private SwaggerBundleConfiguration swaggerBundleConfiguration;
#JsonProperty("swagger")
public void setSwaggerBundleConfiguration (SwaggerBundleConfiguration conf) {
this.swaggerBundleConfiguration = conf;
}
#JsonProperty("swagger")
public SwaggerBundleConfiguration getSwaggerBundleConfiguration () {
return swaggerBundleConfiguration;
}
#JsonProperty("database")
public void setDataSourceFactory(DataSourceFactory factory) {
this.database = factory;
}
#JsonProperty("database")
public DataSourceFactory getDataSourceFactory() {
return database;
}
}
Resource class:
#Path("/companies")
#Api("Companies")
#Produces(MediaType.APPLICATION_JSON)
public class CompaniesResource {
private CompanyDAO companyDAO;
public CompaniesResource(CompanyDAO companyDAO) {
this.companyDAO = companyDAO;
}
#GET
#ApiOperation(
value = "Gives list of all companies",
response = Company.class,
code = HttpServletResponse.SC_OK
)
#UnitOfWork
public List<Company> findAll () {
return companyDAO.findAll();
}
#GET
#Path("/{id}")
#UnitOfWork
public Optional<Company> getById(#PathParam("id") LongParam id) {
return companyDAO.findById(id.get());
}
}
I would be happy for any responses!
I was getting the error Unable to Process JSON.
Troubleshooted more than 4 hours until I found the problem.
The error is caused because of Enum getter.
If you are using Enum fields/getters/setters in your POJO, Jackson will fail to map your JSON to Java Object, and it will crash, leading to the mentioned error.
Looks like your json marshaller is not able to marshall google's Optional class. Try to return Company from the controller, and not Optional:
#GET
#Path("/{id}")
#UnitOfWork
public Company getById(#PathParam("id") LongParam id) {
return companyDAO.findById(id.get()).get();
}

Caused by: java.sql.SQLSyntaxErrorException: ORA-01722: invalid number in JPA HIBERNATE HQL

Having this class
#Entity
public class PriorityAreaKeyword {
public enum PriorityAreaKey {
ALL ("ALL", "ALL DEVICES"),
IOS ("IOS", "IOS"),
ANDROID ("ANDROID","ANDROID");
private final String name;
private final String id;
private PriorityAreaKey(String name, String id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public String getId() {
return id;
}
}
#Id
private Long id;
#Column(name = "key")
#Enumerated(EnumType.STRING)
private PriorityAreaKey key;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public PriorityAreaKey getKey() {
return key;
}
public void setKey(PriorityAreaKey key) {
this.key = key;
}
public List<PriorityArea> getPriorityAreas() {
return priorityAreas;
}
public void setPriorityAreas(List<PriorityArea> priorityAreas) {
this.priorityAreas = priorityAreas;
}
}
I have in the DAO this method that is working fine:
#Override
#SuppressWarnings("unchecked")
public Set<PriorityArea> findPriorityAreas(PriorityAreaKey key) {
String jpql = "from PriorityAreaKeyword as pak where pak.key = :key";
Query query = entityManager.createQuery(jpql);
query.setParameter("key", key);
List<PriorityArea> priorityAreas = query.getResultList();
return new HashSet<PriorityArea>(priorityAreas);
}
I created a view like this v_report_beneficiary_list (id, email, priority_area_key)
/**
*
*/
#Entity
#Table(name = "v_report_beneficiary_list")
public class ReportBeneficiaryItem {
private Long id;
private String email;
private PriorityAreaKey priorityAreaKey;
/**
* #return the id
*/
#Id
public Long getId() {
return id;
}
/**
* #param id the id to set
*/
public void setId(Long id) {
this.id = id;
}
#Column(name = "email")
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#Column(name = "priority_area_key")
public PriorityAreaKey getPriorityAreaKey() {
return priorityAreaKey;
}
public void setPriorityAreaKey(PriorityAreaKey priorityAreaKey) {
this.priorityAreaKey = priorityAreaKey;
}
In the DAO I've created another method like this:
#Su
ppressWarnings("unchecked")
#Override
public List<ReportBeneficiaryItem> findReportProposalXBeneficiary(ProposalExportFilter filter) {
// Create basic query
String jpql = "from " + ReportBeneficiaryItem.class.getName() + " b where b.priorityAreaKey = :key ";
// Create and execute jpa query
Query query = createQuery(jpql);
query.setParameter("key", filter.getPriorityAreaKey());
return query.getResultList();
}
That throws me a throws me an Exception Caused By: java.sql.SQLSyntaxErrorException: ORA-01722: invalid number
You are missing #Enumerated(EnumType.STRING) on ReportBeneficiaryItem#getPriorityAreaKey() as you have on PriorityAreaKeyword#key, so it's expecting numbers (enum index) in the database for that field, but finds strings
#Column(name = "priority_area_key")
#Enumerated(EnumType.STRING)
public PriorityAreaKey getPriorityAreaKey() {
return priorityAreaKey;
}

Categories