Path based on a non-PK unique field in spring-data-rest - java

Given an #Entity declared with the following fields:
#Id
private String idgeo;
private String isoCtryCd;
private String randomField;
with the default spring configuration I get resource paths ending with .../{idgeo}.
Is there an option in the spring configuration to use other (unique) fields as the resource path ending? In my example it'd be .../{isoCtryCd}
Thank you!

Actually this feature will be introduced in Spring Data Rest 2.5. Currently there is a 2.5.0.M1 milestone release containing this feature.
This part of the documentation shows how to use a different entity attribute for item resource uris.
http://docs.spring.io/spring-data/rest/docs/2.5.0.M1/reference/html/#_customizing_item_resource_uris

Related

How to make Spring Data JPA by default naming from camelCase to snake_case unless explicitly specified?

By default, my Spring Boot project had JPA mapping entity properties to table columns by transforming the names from camelCase to snake_case (e.g. from fooBar to foo_bar).
I'm working on an existing DB, where the entity property names were kept as is for the table column names (e.g. from fooBar to fooBar), so I tried to use the #Column annotation to explicitly specify the name:
#Column(name = "fooBar")
private String fooBar;
This wasn't working. I followed the advice given here:
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
My #Column is now successfully taken into account, but I'm losing the camelCase to snake_case implicit transformation on the properties that don't have the #Column the annotation.
Any idea how to transform from camelCase to snake_case by default, unless explicitly specified in the #Column annotation?
Somehow the default JPA behavior of converting to snake case was not working when I injected my custom spring datasource beans for my H2 and postgres repositories. I wanted to convert camel case to snake case by default without explicitly annotating columns while saving objects to DB. Hence adding below property in application.properties worked for me:
spring.jpa.properties.hibernate.physical_naming_strategy: org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy
Note: I am using spring boot version 2.6.2
Automatically transforming property-Names using camelCase (as is the naming convention in Java) to SNAKE_CASE seems to be no longer supported as of Hibernate 5. However, you can write your own Implementation of a NamingStrategy, doing exactly that.
Please check this Stackoverflow-Answer to see how it is done.

Spring Data Elasticsearch - Create keyword field with normalizer

We are using the spring-data-elasticsearch project to interface with our elasticsearch clusters, and have been using it now for around a year. Recently, we moved to elasticsearch 5.x (from 2.x) where we now have the "keyword" datatype.
I would like to index these keywords as lowercase values, which I know can be done with field normalizers. I can't find anywhere in the documentation or online where I can add a normalizer to a field through the annotation based mapping.
E.g
#Field(type = FieldType.keyword, <some_other_param = some_normalizer>)
Is this something that can be done? I know that we can use JSON based mapping definitions as well, so I will fall back to that option if needed, but would like to be able to do it this way if possible.
Any help would be very appreciated!
Since the pull request of #xhaggi has been merged (spring-data-elasticsearch 3.1.3+ or Spring Boot 2.1.1), we have a normalizer field in the #Field annotation.
To use it, we need:
declare a #Field or an #InnerField with params type = FieldType.Keyword, normalizer = "%NORMALIZER_NAME%"
add #Setting(settingPath = "%PATH_TO_NORMALIZER_JSON_FILE%") at the class level.
put the normalizer mapping into a json file at %PATH_TO_NORMALIZER_JSON_FILE%
Example of usage
FYI, for anyone looking at this, the answer is there is not a way to do this at this time.
You can do this, however, by creating your mappings file as JSON in the Elasticsearch format. See:
https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html
You can then create that JSON file and link it to your Domain model with.
#Mapping(mappingPath = "some/path/mapping.json")
Note that this is not, in my experience, compatible with the provided annotation based mapping for fields.
There is a pending issue https://jira.spring.io/browse/DATAES-492 waiting for review.

How to customize the spring-data Repository method names?

I've a bunch of entities that use an underscore prefix before the field names and otherwise use camelcase.
#Entity
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long _id;
private String _firstName;
private String _lastName;
#OneToOne
private Foo _foo;
// … methods omitted
}
The repository
public interface CustomerRepository extends PagingAndSortingRepository<Customer, Long> {
Iterable<Customer> findByFoo(Foo foo);
}
The corresponding fields in the tables also use this naming scheme:
Customer: _id, _firstName, _lastName, _foo__id
Now that I am migrating this project to spring-data, I'm getting many IllegalArgumentExceptions with :
Could not create query metamodel for method
public abstract java.lang.Iterable
com.example.repository.CustomerRepository.findByFoo(com.example.model.Foo)!
Unable to locate Attribute with the given name [foo] on this ManagedType [com.example.model.Customer]
I have no need to change hibernate's naming strategy, but how can I change the query method generation naming algorithm to map "findByFoo" -> "_foo" on the entity, or in JPQL terms "where x._foo__id = ?1"
I'm using old school xml configuration, and no spring boot.
Edit: found this in the docs, which isn't helpful..
"As we treat underscore as a reserved character we strongly advise to
follow standard Java naming conventions (i.e. not using underscores in
property names but camel case instead)."
Perhaps I should refactor the field names, drop the underscore, and then implement a hibernate naming strategy that adds the underscore back in?
I can just repeat what's in the docs (although I'd be interested in the "isn't helpful" part). Use standard Java conventions for your Java code. Use the store specific means to customize the way properties are mapped onto database tables. JPA provides #Column annotations for that.

Is there a way to bypass AuditingEntityListener to set up data for a test?

We've got a Spring project that is using the AuditingEntityListener on our JPA entities:
#EntityListeners(AuditingEntityListener.class)
Our base entity has a lastModifiedDate defined as:
#Column(name = "modified_time")
#LastModifiedDate
#Temporal(TemporalType.TIMESTAMP)
private Date lastModifiedDate;
This value is being set automatically when the entity is saved or updated - which is how we'd like the application to behave. We run into issues, though, when we try to set up data in our test suites because in some situations (not all), we'd like to bypass the automatic setting of this field and set the value ourself. In this specific situation, we're trying to order a bunch of test data and then run a test against it.
Is there any way to bypass or turn off the AuditingEntityListener in order to create test data?
Declaring
#MockBean
private AuditingHandler auditingHandler
in your test should prevent the #LastModifiedDate from having any effect.
I can imagine the following solution: create two persistence.xml files - one for production and another for testing purposes:
the production related persistence.xml includes reference to orm_production.xml mapping file that specifies AuditingEntityListener with entity-listener attribute
the tests related persistence.xml may include reference to orm_test.xml maping file that specifies AuditingEntityListener with entity-listener attribute. Additionally, your base entity needs to be defined entirely within xml mapping file and specify:
metadata-complete attribute: tells the provider to ignore in-code annotations
exclude-default-listeners attribute: tells the provider to ignore entity listeners but only for the corresponding base entity

Xtend's _field naming and SpringData's repository naming conventions

It seems that the naming conventions between Xtend and Spring Data are incompatible.
For example:
// User.xtend
class User {
#Property
var Long id;
}
interface UserRepository extends JpaRepository<User> {
public User findById(Long id)
}
The #Property annotation renames id to _id, which causes Spring Data to fail, claiming No property id found
Is there a way to either:
Suppress Xtend's renaming of the field
"Teach" Spring Data about the naming convention (Looking for a field? Add an underscore)
Instruct Spring Data to use property-access, rather than field-access for the property resolution?
Any of these would solve this issue, I believe.
Since 2.7.3 the #Property annotation has been superceded by #Accessors, which no longer prepends the fields with an underscore.
Before 2.7.3 you have to build your own #Property annotation which doesn't prepend an underscore to the field's name.
See http://www.eclipse.org/xtend/documentation.html#activeAnnotations
(updated)

Categories