JOOQ transactions with DefaultTransactionProvider without functions - java

I'm aware that I can use DefaultTransactionProvider with DSLContext and lambdas like this
DSL.using(configuration)
.transaction(ctx -> {
DSL.using(ctx)
.update(TABLE)
.set(TABLE.COL, newValue)
.where(...)
.execute();
});
However I would like to control my transaction outside the scope of a code block (but still using DefaultTransactionProvider as its behavior with checkpointing and such is what I'm looking for). More like this
configuration.transactionProvider().begin(transactionContext);
DSL.using(configuration)
.update(TABLE)
.set(TABLE.COL, newValue)
.where(...)
.execute();
configuration.transactionProvider().commit(transactionContext);
Is this possible or will I need to implement the transaction SPI myself to accomplish this?

As of jOOQ 3.8, this is not possible out of the box. There is a pending feature request for this:
https://github.com/jOOQ/jOOQ/issues/5376
Your code will probably work:
configuration.transactionProvider().begin(transactionContext);
DSL.using(configuration)
.update(TABLE)...
configuration.transactionProvider().commit(transactionContext);
But beware that you're calling SPI methods, not API methods. These methods have not been designed for direct access by you as an API consumer. They're designed for implementation and injection into the jOOQ SPI context in the Configuration. If you want to continue this path, your TransactionProvider will need to access the Configuration.connectionProvider() and modify its state in order to produce always the right connection until commit() or rollback() is called.
See also a related discussion on the jOOQ user group:
https://groups.google.com/forum/#!msg/jooq-user/1JwWMChD2SM/NHUhSnI8AgAJ

Related

LazyInitializationException in unit tests under Spring-Data/Spring-Boot

My unit tests are seeing org.hibernate.LazyInitializationException: could not initialize proxy [org.openapitools.entity.MenuItem#5] - no Session. I'm not sure why they expect a session in a unit test. I'm trying to write to an in-memory h2 database for the unit tests of my Controller classes that implement the RESTful APIs. I'm not using any mock objects for the test, because I want to test the actual database transactions. This worked fine when I was using Spring-Boot version 1.x, but broke when I moved to version 2. (I'm not sure if that's what caused the tests to break, since I made lots of other changes. My point is that my code has passed these tests already.)
My Repositories extend JPARepository, so I'm using a standard Hibernate interface.
There are many answers to this question on StackOverflow, but very few describe a solution that I could use with Spring-Data.
Addendum: Here's a look at the unit test:
#Test
public void testDeleteOption() throws ResponseException {
MenuItemDto menuItemDto = createPizzaMenuItem();
ResponseEntity<CreatedResponse> responseEntity
= adminApiController.addMenuItem(menuItemDto);
final CreatedResponse body = responseEntity.getBody();
assertNotNull(body);
Integer id = body.getId();
MenuItem item = menuItemApiController.getMenuItemTestOnly(id);
// Hibernate.initialize(item); // attempted fix blows up
List<String> nameList = new LinkedList<>();
for (MenuItemOption option : item.getAllowedOptions()) { // blows up here
nameList.add(option.getName());
}
assertThat(nameList, hasItems("pepperoni", "olives", "onions"));
// ... (more code)
}
My test application.properties has these settings
spring.datasource.url=jdbc:h2:mem:pizzaChallenge;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username=pizza
spring.datasource.password=pizza
spring.jpa.show-sql=true
This is not standard Hibernate, but spring data. You have to understand that Hibernate uses lazy loading to avoid loading the whole object graph from the database. If you close the session or connection to the database e.g. by ending a transaction, Hibernate can't lazy load anymore and apparently, your code tries to access state that needs lazy loading.
You can use #EntityGraph on your repository to specify that an association should be fetched or you avoid accessing the state that isn't initialized outside of a transaction. Maybe you just need to enlarge the transaction scope by putting #Transactional on the method that calls the repository and accesses the state, so that lazy loading works.
I found a way around this. I'm not sure if this is the best approach, so if anyone has any better ideas, I'd appreciate hearing from them.
Here's what I did. First of all, before reading a value from the lazy-loaded entity, I call Hibernate.initialize(item);
This throws the same exception. But now I can add a property to the test version of application.properties that says
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
Now the initialize method will work.
P.S. I haven't been able to find a good reference for Spring properties like this one. If anyone knows where I can see the available properties, I'd love to hear about it. The folks at Spring don't do a very good job of documenting these properties. Even when they mention a specific property, they don't provide a link that might explain it more thoroughly.

Is it possible to intercept a save or load event in spring-data-elasticsearch?

In spring-data-jpa, we can use JPA's annotations like #PrePersist and friends to intercept save/load events.
In spring-data-mongodb, for the same purpose we can use lifecycle events.
Is there anything similar in spring-data-elasticsearch?
At the moment there are no lifecycle hooks in spring-data-elasticsearch like they exist in spring-data-mongodb. It sure would be nice to have them.
I opened issue for this.
Edit:
As Roman wrote in his answer, this has been implemented in version 4.0
To be honest I don't know elasticsearch but as it is Spring Data I would suggest you use an EventHandler like this:
#Component
#RepositoryEventHandler(YourDomainClass.class)
public class YourDomainClassEventHandler {
#HandleBeforeCreate
public void handleYourDomainClassCreate(YourDomainClass yourDomainClass) {
//do some action
}
}
There are also annotations like #HandleBeforeSave, #HandleAfterSave and a few more. It's part of spring-data-rest-core library.
EntityCallback support was implemented a few months ago, see https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#entity-callbacks
Currently, after-save, after-convert, before-convert entity callbacks are supported, both reactive and blocking.

Use placeholders in feature files

I would like to use placeholders in a feature file, like this:
Feature: Talk to two servers
Scenario: Forward data from Server A to Server B
Given MongoDb collection "${db1}/foo" contains the following record:
"""
{"key": "value"}
"""
When I send GET "${server1}/data"
When I forward the respone to PUT "${server2}/data"
Then MongoDB collection "${db2}/bar" MUST contain the following record:
"""
{"key": "value"}
"""
The values of ${server1} etc. would depend on the environment in which the test is to be executed (dev, uat, stage, or prod). Therefore, Scenario Outlines are not applicable in this situation.
Is there any standard way of doing this? Ideally there would be something which maintains a Map<String, String> that can be filled in a #Before or so, and runs automatically between Cucumber and the Step Definition so that inside the step definitions no code is needed.
Given the following step definitions
public class MyStepdefs {
#When("^I send GET "(.*)"$)
public void performGET(final String url) {
// …
}
}
And an appropriate setup, when performGET() is called, the placeholder ${server1} in String uri should already be replaced with a lookup of a value in a Map.
Is there a standard way or feature of Cucumber-Java of doing this? I do not mind if this involves dependency injection. If dependency injection is involved, I would prefer Spring, as Spring is already in use for other reasons in my use case.
The simple answer is that you can't.
The solution to your problem is to remove the incidental details from your scenario all together and access specific server information in the step defintions.
The server and database obviously belong together so lets describe them as a single entity, a service.
The details about the rest calls doesn't really help to convey what you're
actually doing. Features don't describe implementation details, they describe behavior.
Testing if records have been inserted into the database is another bad practice and again doesn't describe behavior. You should be able to replace that by an other API call that fetches the data or some other process that proves the other server has received the information. If there are no such means to extract the data available you should create them. If they can't be created you can wonder if the information even needs to be stored (your service would then appear to have the same properties as a black hole :) ).
I would resolve this all by rewriting the story such that:
Feature: Talk to two services
Scenario: Forward foobar data from Service A to Service B
Given "Service A" has key-value information
When I forward the foobar data from "Service A" to "Service B"
Then "Service B" has received the key-value information
Now that we have two entities Service A and Service B you can create a ServiceInformationService to look up information about Service A and B. You can inject this ServiceInformationService into your step definitions.
So when ever you need some information about Service A, you do
Service a = serviceInformationService.lookup("A");
String apiHost = a.getApiHost():
String dbHost = a.getDatabaseHOst():
In the implementation of the Service you look up the property for that service System.getProperty(serviceName + "_" + apiHostKey) and you make sure that your CI sets A_APIHOST and A_DBHOST, B_APIHOST, B_DBHOST, ect.
You can put the name of the collections in a property file that you look up in a similar way as you'd look up the system properties. Though I would avoid direct interaction with the DB if possible.
The feature you are looking for is supported in gherkin with qaf. It supports to use properties defined in properties file using ${prop.key}. In addition it offers strong resource configuration features to work with different environments. It also supports web-services

spring cloud contract dsl specify path parameter

I am trying to create a contract for a GET request and I'd like to use a path parameter, that can be reused in the response as well. Is this at all possible? I can only find examples for POST, query parameters and body's.
So if I want to define a contract that requests an entity i.e. /books/12345-6688, I want to reuse the specified ID in the response.
How do I create a contract for something like this?
Possible since Spring Cloud Contract 1.2.0-RC1 (fixed in this issue).
response {
status 200
body(
path: fromRequest().path(),
pathIndex: fromRequest().path(1) // <-- here
)
}
See the docs.
Nope that's not possible due to https://github.com/tomakehurst/wiremock/issues/383 . Theoretically you could create your own transformer + override the way stubs are generated in Spring Cloud Contract. That way the WireMock stubs would contain a reference to your new transformer (like presented in the WireMock docs - http://wiremock.org/docs/extending-wiremock/). But it sounds like a lot of work for sth that seems not really that necessary. Why do you need to do it like this? On the consumer side you want to test the integration, right? So just hardcode some values in the contract instead of referencing them and just check if you can parse those values.
UPDATE:
If you just need to parametrize the request URL but don't want to reference it in the response you can use regular expressions like here - https://cloud.spring.io/spring-cloud-contract/single/spring-cloud-contract.html#_regular_expressions
UPDATE2:
Like #laffuste has mentioned, starting from RC1 you can reference a concrete path element

How to get the underlying connection inside a transaction using jOOQ?

I'm using jOOQ inside an existing project which also uses some custom JDBC code. Inside a jOOQ transaction I need to call some other JDBC code and I need to pass through the active connection so everything gets inside the same transaction.
I don't know how to retrieve the underlying connection inside a jOOQ transaction.
create.transaction(configuration -> {
DSLContext ctx = DSL.using(configuration);
// standard jOOQ code
ctx.insertInto(...);
// now I need a Connection
Connection c = ctx.activeConnection(); // not real, this is what I need
someOtherCode(c, ...);
});
Reading the docs and peeking a bit on the source code my best bet is this:
configuration.connectionProvider().acquire()
But the name is a bit misleading in this particular use case. I don't want a new connection, just the current one. I think this is the way to go because the configuration is derived and I will always get the same connection, but I'm not sure and I can't find the answer in the documentation.
jOOQ's API makes no assumptions about the existence of a "current" connection. Depending on your concrete implementations of ConnectionProvider, TransactionProvider, etc., this may or may not be possible.
Your workaround is generally fine, though. Just make sure you follow the ConnectionProvider's SPI contract:
Connection c = null;
try {
c = configuration.connectionProvider().acquire();
someOtherCode(c, ...);
}
finally {
configuration.connectionProvider().release(c);
}
The above is fine when you're using jOOQ's DefaultTransactionProvider, for instance.
Note there is a pending feature request #4552 that will allow you to run code in the context of a ConnectionProvider and its calls to acquire() and release(). This is what it will look like:
DSL.using(configuration)
.connection(c -> someOtherCode(c, ...));

Categories

Resources