Requirement
I've been asked to retrieve the value of a query annotation from a custom property stored in the application.properties file.
Prievious attempt
I tried to use #Value without success
#Repository
public interface FooRepository
extends JpaRepository<Foo, Long> {
#Value("${db.queries.distance}")
String distanceQuery; // this raises an error
#Query(nativeQuery = true, value =distanceQuery)
...
Eclipse marks "distanceQuery" and states
The blank final field distanceQuery may not have been initialized
And force me to initialize the variable as follows
public static final Double distanceQuery = null;
Unfortunately it's not what I want
Question
Is there a workaround to fix this issue?
Thank you in advance!
Instead of defining in a properties file, you can define query in a constants java file and can get value as below
#Query(nativeQuery = true, value =Constants.DISTANCE_QUERY)
Related
I have a table with a clob in an oracle 19 database which I try to fetch with a native query using a #Query annotation with a projection from a Spring boot 2.7.4 application. I get the following error message:
java.lang.UnsupportedOperationException: Cannot project jdk.proxy2.$Proxy281 implementing java.sql.Clob,org.hibernate.engine.jdbc.WrappedClob,java.io.Serializable to java.lang.String; Target type is not an interface and no matching Converter found
The query from my repository class:
#Query(
value = """
select submission_id as "submissionId", text as "textAnswer"
from answer
where answer_id = :answerId
""",
nativeQuery = true)
public MyDTO findDTO(Long answerId);
My interface which I use for the projection:
public interface MyDTO {
String getTextAnswer();
}
From my domain object annotated with #Entity:
private String textAnswer;
My testcase which reproduce which reproduce this error. If I comment out the line with a.getTextAnswer() it runs ok.
#Test
public void findFormPublishedAnswersInterfaceDTOById() {
FormPublishedAnswersInterfaceDTO a = answerRepository.findFormPublishedAnswersInterfaceDTOById(21540241L);
assertEquals("test", a.getTextAnswer());
}
I have tried different hints I found by the help of google :) like annotating private String textAnswer with #Lob, #Type(type = "text") and #Column(name = "text", columnDefinition = "CLOB") without any luck.
If you read the exception carefully, you should understand that the JDBC driver reports that the type is a Clob, so your DTO must look like this instead:
public interface MyDTO {
Clob getTextAnswer();
}
Is there a way to validate application.properties (or yml) if the properties match Java bean that it is mapped to via #ConfigurationProperties - so that if there is a typo in an attribute, exception will be thrown?
I tried using #Validated but it works only if every property has #NotNull annotation - but this is not exactly what I want to achieve... there may be some nullable properties in the config and I still want to "validate" them
I just spent 2 hours debugging an issue and I found out, the problem is that I misspelled an attribute name
e.g. application.yml
property1: 1
properrrrrty2: 2
#Configuration
#ConfigurationProperties
public class AppConfig {
private String property1;
private String property2; // <--- this property does not match due to typo in application.yml
}
A)
If you want to be sure that always a property exists then use #Validated with #NotNull for that property. #NotNull will complain if it does not find that property. You can still have the property there with an empty value if that is what you mean with nullable properties and NotNull will not complain.
You can't say I want it to be able to be nullable but also the validator should complain when that property is null.
So to sum things up.
#NotEmpty property must exist and also not have an empty value
#NotNull property must just exist. It does not care if it exists with an empty value.
That's why I insist you go with NotNull for your requirements.
B)
Also I can think of another way to handle that.
#Component
public class AppConfig {
#Value("${property1}")
private String property1;
#Value("${property2}")
private String property2;
}
Using injection with #Value, spring will fail to initialize the singleton AppConfig during application startup if some property with exactly the same name does not exist on properties file, therefore you will be informed that no property with that name exists and the application will not start up.
You can specify ignoreUnknownFields = false to ensure that no unknown properties are defined under the corresponding prefix. (docs):
Flag to indicate that when binding to this object unknown fields should be ignored. An unknown field could be a sign of a mistake in the Properties.
Borrowing from your example:
#Configuration
#ConfigurationProperties(prefix = "myapp", ignoreUnknownFields = false)
public class AppConfig {
private String property1;
private String property2;
}
This means myapp.property1 and myapp.property2 are allowed but not required to be set, so they remain nullable.
Any other set property with the myapp prefix (such as myapp.properrrrrty2=2) will cause a startup failure and the offending property name will be logged in the exception.
I read a code generated by khipster and in one dataclass I found such fragment:
import javax.validation.constraints.NotNull
data class MyDTO(
var id: Long? = null,
#get: NotNull
var name: String? = null,
What does #get:NotNull annotation mean? As far as I understand #get means that I want to annotate the getter of name property and NotNull is a validation annotation which mean that the thing can't be set to null. But how the two work together? It doesn't make any sense to annotate getter with annotation which means this can't be set to null, because getter can't be set. It would make more sens to use NotNull annotation on setter.
#NotNull on a method means it can't return null. So in particular annotating a setter with it makes no sense; annotating the setter's parameter does.
If you use the decompile feature of IntelliJ ( please check this answer )
Kotlin Code:
#get: NotNull
var uid: String? = null
Decompiled Code:
import javax.validation.constraints.NotNull;
import org.jetbrains.annotations.Nullable;
#Nullable
private String uid;
#NotNull
#Nullable
public final String getUid() {
return this.uid;
}
public final void setUid(#Nullable String var1) {
this.uid = var1;
}
What does #get:NotNull annotation mean?
A quick answer: Please put #NotNull annotation on the top of the getter function
!! Please be aware that there is also #Nullable annotation added to the getter function because of the "?" at the end of the variable definition
As you notice from import it is added by IntelliJ
As detailed answer: I could redirect you to "Use-Site Target Declarations"
Bealdung
Blog post
Finally, I would like to express my experience on that, I had both #Nullable and #NotNull annotation on uid field (you could see on decompiled code), I could set that field to null
Hi I am using Spring Data JPA and want to use feature generate query from method name. I have a field active in DB which have only value 0 and 1. I want to fetch all data with which have active value is 1.
This is a constant value so i don't want to pass this value as method arguments.
please suggest what will be the method for the same.
example:
I have a entity EmailRef
public class EmailRef {
/* other vareialbe */
#Column(name="is_active") /* this is the field which value is 0 and 1 in DB*/
private Integer active;
/* setter getter method */
}
This is the repository for where I want to write method which will fetch all data for which active is 1;
public interface EmailRefRepositry extends JpaRepository<EmailRef, Long> {
#Query("select * from email_reference where is_active=1") /* this is the query I want to convert into method*/
List<EmailRef> findByActive(); /*I want to write method like that which will fetch all data form table where active field value is 1*/
}
I am stuck for constant vale please suggest
Thanks
Sudhanshu
If you could change that Integer to a boolean, you could be doing something like:
In your entity:
private Boolean active;
In your repo:
List<EmailRef> findByActiveIsTrue();
Try this:
public interface EmailRefRepositry extends JpaRepository<EmailRef, Long> {
#Query("select e from EmailRef e where e.active=1")
List<EmailRef> findOnlyActiveWithQuery();
default List<EmailRef> findOnlyActive() {
findByActive(1);
}
default List<EmailRef> findNotActive() {
findByActive(0);
}
List<EmailRef> findByActive(Integer active);
}
I don't think you can do what you want using Spring JPAs magic where is derives the query from the method name (unless you are able to do as #kimy82 suggests in their solution). You can of course use the #Query annotation on your repository method though. However the one you have defined won't work because it is a native query and you have no specified that. Here are two possible fixes to your Query annotation although I would recommend the first:
#Query("select e from EmailRef e where e.active=1")
or
#Query("select * from email_reference where is_active=1", nativeQuery=true)
I am using Spring Framework as my back end
I have define know as Entity class The Entity class know contain 5 Fields
Below is the class , The code below dose not have setter getter part to make shorter and cleaner
#Entity
#Table(name="TblKnow")
public class Know {
#Id
private Double idKnow;
private String SubjectKnow;
private String BodyKnow;
private String ImgKnow;
private double CountView;
In JpaRepository interface i want to only query two column not all of columns.
public interface KnowRepository extends JpaRepository<Know,Double> {
#Query("SELECT idKnow,SubjectKnow FROM Know")
public Page<Know> findCByOrderByIdKnowDesc(Pageable pageable);
Problem: i try to run but i get below exception
java.lang.IllegalArgumentException: Cannot create TypedQuery for query with more than one return using requested result type [java.lang.Long]
But if i use without below query it is fine
public Page<Know> findAllByOrderByIdKnowDesc(Pageable pageable);
You can create a custom constructor and use that to select only some fields in JPA query.
public Know(Double idKnow, String SubjectKnow) {
this.idKnow = idKnow;
this.SubjectKnow = SubjectKnow;
}
And the use this constructor in JPA query. Make sure you use complete path of class with package.
#Query("SELECT NEW packagePath.Know(idKnow,SubjectKnow) FROM Know")
query :
public Page<Know> findAllByOrderByIdKnowDesc(Pageable pageable);
works dut to you select Know objects with fields that are mapped correct into Know class (and after wrapped into Page).
with query :
#Query("SELECT idKnow,SubjectKnow FROM Know")
public Page<Know> findCByOrderByIdKnowDesc(Pageable pageable);
returns some custome bean/object that spring data can't map in correct way into Know class (as you declared it as expected return class wrapped into Page). add counstructor into Know with idKnow,SubjectKnow fields , or you can wrap it into some DTO with idKnow,SubjectKnow fields.