Mapping #Json property with JDBI - jdbi

According to JDBI document https://jdbi.org/#_jackson_2, it seems that it's quite straight forward to have a json property of your object model, however I've tried the following and it ran into many issues.
DB: Postgres with a column type of Jsonb
class Event {
private String name;
#Json
private EventProperty jsonProperty;
...
}
Datasource has been configured with
#Bean
public Jdbi jdbi(TransactionAwareDataSourceProxy eventStoreTxAwareDataSourceProxy) {
Jdbi jdbi = Jdbi.create(eventStoreTxAwareDataSourceProxy);
jdbi.installPlugin(new PostgresPlugin());
jdbi.installPlugin(new Jackson2Plugin());
}
SQL for binding list of insertion
INSERT INTO event (name, json_property)
VALUES (
:name,
:jsonProperty)
When running the code to insert, the following error occurred:
org.jdbi.v3.core.statement.UnableToCreateStatementException: no argument factory for type com.EventProperty [statement:"INSERT INTO event (...]
If I created EventPropertyArgumentFactory and using Jackson ObjectMapper and writeValueAsString then I can save it to DB. However, when retrieving it back from DB by
try (Handle handle = jdbi.open()) {
EventDao dao = handle.attach(EventDao.class);
return dao.findByName(name);
}
throws the following errors
java.lang.ClassCastException: Cannot cast org.postgresql.util.PGobject to com.EventProperty
I thought all I needed to do is declare the field annotated with #Json, the DB column has to be json/jsonb type and install the plugins, but seems like this is not the case?
Anyone has tried this successfully, without having to define custom row mapper and argument factory implementation?
Thanks

The documentation says:
// use #Json qualifier:
...
// also works on bean or property-mapped objects:
class MyBean {
private final MyJson property;
#Json
public MyJson getProperty() { return ...; }
}
I've checked and it's unfortunate but #Json only works when placed on a property( i.e. getter or setter) and not on a field.
You can make your work easier if you use Lombok library.
Modify lombok.config file by adding this line:
lombok.copyableannotations += org.jdbi.v3.json.Json
Now in bean declaration you can do this:
#Data // will generate setters and getters among other things
class Event {
private String name;
#Json // will be copied onto getter and setter due to config change we made
private EventProperty jsonProperty;
...
}
Have fun!

Not sure if you've figured this out by now but I just ran into this same issue and finally figured it out.
Basically, you just have to add the annotation on the getter or setter of the class, not the top-level field.
class Event {
private String name;
private EventProperty jsonProperty;
...
#Json
public getEventProperty() {
return jsonProperty;
}
}

Related

Extending SimpleNeo4jRepository in SDN 6

In SDN+OGM I used the following method to extend the base repository with additional functionality, specifically I want a way to find or create entities of different types (labels):
#NoRepositoryBean
public class MyBaseRepository<T> extends SimpleNeo4jRepository<T, String> {
private final Class<T> domainClass;
private final Session session;
public SpacBaseRepository(Class<T> domainClass, Session session) {
super(domainClass, session);
this.domainClass = domainClass;
this.session = session;
}
#Transactional
public T findOrCreateByName(String name) {
HashMap<String, String> params = new HashMap<>();
params.put("name", name);
params.put("uuid", UUID.randomUUID().toString());
// we do not use queryForObject in case of broken data with non-unique names
return this.session.query(
domainClass,
String.format("MERGE (x:%s {name:$name}) " +
"ON CREATE SET x.creationDate = timestamp(), x.uuid = $uuid " +
"RETURN x", domainClass.getSimpleName()),
params
).iterator().next();
}
}
This makes it so that I can simply add findOrCreateByName to any of my repository interfaces without the need to duplicate a query annotation.
I know that SDN 6 supports the automatic creation of a UUID very nicely through #GeneratedValue(UUIDStringGenerator.class) but I also want to add the creation date in a generic way. The method above allows to do that in OGM but in SDN the API changed and I am a bit lost.
Well, sometimes it helps to write down things. I figured out that the API did not change that much. Basically the Session is replaced with Neo4jOperations and the Class is replaced with Neo4jEntityInformation.
But even more important is that SDN 6 has #CreatedDate which makes my entire custom code redundant.

spring boot - why is #valid not working on controller for type?

I have Spring Boot application with a rest endpoint in a #RestController annotated class that is something like this:
#Postmapping(path = "<url>")
private #ResponseBody ResponseEntity<?> methodName(
otherParameters otherParameters,
#Valid #RequestBody Entity entity,
Errors errors) {
if(errors.hasErrors()) {
// log something
// do something
}
// rest of the controller
}
The Entity class is something like this:
public class Entity {
#Pattern(regexp = "[^<>&]+")
private String someString;
// getters and setters
}
But when I try to reach the controller with someString as some&tring, the #Valid annotation does not seem to work.
This is accessible only from a rest call. There are no forms that use this action.
There is no spring-security implementation in this application at the moment.
What am I missing here?
Be sure to add #Valid on the member fields of your pojos if those fields represent pojo's themselves, otherwise the validation does not propagate.
I think you are missing the object add to the page.
check the following code.
check 1 :
// on controller side
#GetMapping("/registration")
public String registration(Model model) {
model.addAttribute("entity", new Entity());
return "registration";
}
#PostMapping("/registration")
public String registration(#ModelAttribute("entity") Entity entity, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "registration"; // stay on that page here
}
return "login"; // after no error go here
}
use this entity in form on the page where you want to access the validation
<form action="#" th:action="#{/registration}" th:object="${entity}" method="post" class="m-t">
check 2 :
both the get and post method must be the same name for the object created like **entity**

Is it possible to Mock and ignore properties

I'm changing our identity strategy and we're using an ID that is generated before the Entity is written to the database. This change is causing some of our tests to fail due to the way we're mocking some service calls.
TimeLog timeLog = buildTimeLog('123456', mockEmployeeId);
TimeLog mockTimeLog = buildTimeLog('123456', mockEmployeeId);
when(this.timeLogService.save(mockTimeLog)).thenReturn(timeLog);
When the test makes the call to the Controller, the bound entity in the Controller gets a different ID than the mock that is expected because the Entity generates the ID. Whereas before, the database generated the ID so the mocks worked.
If there is a way to tell Mockito to ignore a property in the expectation? That would solve the problem and the test would still be valid. Otherwise, other approaches are welcome.
You can't tell mockito to ignore a property in an expectation because it's using the java "equals" method... You can define an equals method in TimeLog that igonres ID but I suspect that won't give you what you want. The other approach is, instead of trying to tell mockito what not to verify, define explicitly what it is to verify using a hamcrest matcher. Define a hamcrest matcher which just matches the fields you want to verify i.e. all fields other than ID. So something like:
private class TimeLogMatcher extends TypeSafeMatcher<TimeLog> {
private final EmployeeId employeeId;
public TimeLogMatcher(EmployeeId employeeId) {
this.employeeId = employeeId;
}
#Override
public void describeTo(Description description) {
description.appendText("TimeLog with employeeId=" + employeeId);
}
#Override
public boolean matchesSafely(TimeLog item) {
return employeeId.equals(item.getEmployeeId());
}
}
And then instead of calling whatever your "buildTimeLog" method is doing call into the mockito Matchers class like:
TimeLog timeLog = Matchers.argThat(new TimeLogMatcher(mockEmployeeId));
Or alternatively you could always use an Answer object:
when(this.timeLogService.save(any(TimeLog.class)).thenAnswer(new Answer<TimeLog> {
public TimeLog answer(InvocationOnMock invocation) throws Throwable {
TimeLog receivedTimeLog = invocation.getArgumentAt(0, TimeLog.class);
assertThat(receivedTimeLog.getEmployeeId(), equalTo(mockEmployeeId));
return timeLog;
}
});
Does that all make sense?

What's the lazy strategy and how does it work?

I have a problem. I'm learning JPA. I'm using embedded OpenEJB container in unit tests, but only working is #OneToMany(fetch=EAGER). Otherwise is the collection allways null. I haven't found, how the lazy strategy works, how the container fills the data and in which circumstances triggers the container the loading action?
I have read, that the action triggers when the getter is being called. But when I have the code:
#OneToMany(fetch = LAZY, mappedBy="someField")
private Set<AnotherEntities> entities = new Set<AnotherEntities>();
...
public Set<AnotherEntities> getEntities() {
return entities;
}
I'm always getting null. I thing, the LAZY strategy cannot be tested with embedded container. The problem might be also in the bidirectional relation.
Does have anybody else similar expiriences with the JPA testing?
Attachments
The real test case with setup:
#RunWith(UnitilsJUnit4TestClassRunner.class)
#DataSet("dataSource.xml")
public class UnitilsCheck extends UnitilsJUnit4 {
private Persister prs;
public UnitilsCheck() {
Throwable err = null;
try {
Class.forName("org.hsqldb.jdbcDriver").newInstance();
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
props.put("ds", "new://Resource?type=DataSource");
props.put("ds.JdbcDriver", "org.hsqldb.jdbcDriver");
props.put("ds.JdbcUrl", "jdbc:hsqldb:mem:PhoneBookDB");
props.put("ds.UserName", "sa");
props.put("ds.Password", "");
props.put("ds.JtaManaged", "true");
Context context = new InitialContext(props);
prs = (Persister) context.lookup("PersisterImplRemote");
}
catch (Throwable e) {
e.printStackTrace();
err = e;
}
TestCase.assertNull(err);
}
#Test
public void obtainNickNamesLazily() {
TestCase.assertNotNull(prs);
PersistableObject po = prs.findByPrimaryKey("Ferenc");
TestCase.assertNotNull(po);
Collection<NickNames> nicks = po.getNickNames();
TestCase.assertNotNull(nicks);
TestCase.assertEquals("[Nick name: Kutyafája, belongs to Ferenc]", nicks.toString());
}
}
The bean Presister is the bean mediating access to the entity beans. The crucial code of class follows:
#PersistenceUnit(unitName="PhonePU")
protected EntityManagerFactory emf;
public PhoneBook findByPrimaryKey(String name) {
EntityManager em = emf.createEntityManager();
PhoneBook phonebook = (PhoneBook)em.find(PhoneBook.class, name);
em.close();
return phonebook;
}
Entity PhoneBook is one line of phone book (also person). One person can have zero or more nick names. With EAGER strategy it works. With LAZY the collection is allways null. May be the problem is in the detaching of objects. (See OpenEJB - JPA Concepts, part Caches and detaching.) But in the manual is written, that the collection can be sometimes (more like manytimes) empty, but not null.
The problem is in the life cycle of an entity. (Geronimo uses OpenJPA, so le't see OpenJPA tutorial, part Entity Lifecycle Management.) The application uses container managed transactions. Each method call on the bean Persiser runs in an own transation. And the persistency context depends on the transaction. The entity is disconnected from its context at the end of the transaction, thus at the end of the method. I tried to get the entity and on second line in the same method to get the collection of nick names and it worked. So the problem was identifyed: I cannot get additionally any entity data from the data store without re-attaching the entity to some persistency context. The entity is re-attached by the EntityManager.merge() method.
The code needs more correctures. Because the entity cannot obtain the EntityManager reference and re-attach itself, the method returning nick names must be moved to the Persister class. (The comment Heureka marks the critical line re-attaching the entity.)
public Collection<NickNames> getNickNamesFor(PhoneBook pb) {
//emf is an EntityManagerFactory reference
EntityManager em = emf.createEntityManager();
PhoneBook pb = em.merge(pb); //Heureka!
Collection<NickNames> nicks = pb.getNickNames();
em.close();
return nicks;
}
The collection is then obtained in this way:
//I have a PhoneBook instance pb
//pb.getNickNames() returns null only
//I have a Persister instance pe
nicks = pe.getNickNames(pb);
That's all.
You can have a look at my second question concerning this topic I'have asked on this forum. It is the qustion OpenJPA - lazy fetching does not work.
How I would write the code
#Entity
public class MyEntity {
#OneToMany(fetch = LAZY, mappedBy="someField")
private Set<AnotherEntities> entities;
// Constructor for JPA
// Fields aren't initalized here so that each em.load
// won't create unnecessary objects
private MyEntity() {}
// Factory method for the rest
// Have field initialization with default values here
public static MyEntity create() {
MyEntity e = new MyEntity();
e.entities = new Set<AnotherEntities>();
return e;
}
public Set<AnotherEntities> getEntities() {
return entities;
}
}
Idea no 2:
I just thought that the order of operations in EAGER and LAZY fetching may differ i.e. EAGER fetching may
Declare field entities
Fetch value for entities (I'd assume null)
Set value of entities to new Set<T>()
while LAZY may
Declare field `entities
set value of entities to new Set<T>()
Fetch value for entities (I'd assume null)'
Have to find a citation for this as well.
Idea no 1: (Not the right answer)
What if you'd annotate the getter instead of the field? This should instruct JPA to use getters and setters instead of field access.
In the Java Persistence API, an entity can have field-based or
property-based access. In field-based access, the persistence provider
accesses the state of the entity directly through its instance
variables. In property-based access, the persistence provider uses
JavaBeans-style get/set accessor methods to access the entity's
persistent properties.
From The Java Persistence API - A Simpler Programming Model for Entity Persistence

using a Singleton to pass credentials in a multi-tenant application a code smell?

I'm currently working on a multi-tenant application that employs Shared DB/Shared Schema approach. IOW, we enforce tenant data segregation by defining a TenantID column on all tables. By convention, all SQL reads/writes must include a Where TenantID = '?' clause. Not an ideal solution, but hindsight is 20/20.
Anyway, since virtually every page/workflow in our app must display tenant specific data, I made the (poor) decision at the project's outset to employ a Singleton to encapsulate the current user credentials (i.e. TenantID and UserID). My thinking at the time was that I didn't want to add a TenantID parameter to each and every method signature in my Data layer.
Here's what the basic pseudo-code looks like:
public class UserIdentity
{
public UserIdentity(int tenantID, int userID)
{
TenantID = tenantID;
UserID = userID;
}
public int TenantID { get; private set; }
public int UserID { get; private set; }
}
public class AuthenticationModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.AuthenticateRequest +=
new EventHandler(context_AuthenticateRequest);
}
private void context_AuthenticateRequest(object sender, EventArgs e)
{
var userIdentity = _authenticationService.AuthenticateUser(sender);
if (userIdentity == null)
{
//authentication failed, so redirect to login page, etc
}
else
{
//put the userIdentity into the HttpContext object so that
//its only valid for the lifetime of a single request
HttpContext.Current.Items["UserIdentity"] = userIdentity;
}
}
}
public static class CurrentUser
{
public static UserIdentity Instance
{
get { return HttpContext.Current.Items["UserIdentity"]; }
}
}
public class WidgetRepository: IWidgetRepository{
public IEnumerable<Widget> ListWidgets(){
var tenantId = CurrentUser.Instance.TenantID;
//call sproc with tenantId parameter
}
}
As you can see, there are several code smells here. This is a singleton, so it's already not unit test friendly. On top of that you have a very tight-coupling between CurrentUser and the HttpContext object. By extension, this also means that I have a reference to System.Web in my Data layer (shudder).
I want to pay down some technical debt this sprint by getting rid of this singleton for the reasons mentioned above. I have a few thoughts on what a better implementation might be, but if anyone has any guidance or lessons learned they could share, I would be much obliged.
CurrentUser isn't quite a singleton. I'm not exactly sure what you'd call it. (A singleton by definition can only exist one at a time, and any number of UserIdentity instances can be created at will by outside code and coexist without any issues.)
Personally, i'd take CurrentUser.Instance and either move it to UserIdentity.CurrentUser, or put it together with whatever similar "get the global instance" methods and properties you have. Gets rid of the CurrentUser class, at least. While you're at it, make the property settable at the same place -- it's already settable, just in an way that (1) would look like magic if the two classes weren't shown right next to each other, and (2) makes changing how the current user identity is set later harder.
Doesn't get rid of the global, but you're not really gonna get around that without passing the UserIdentity to every function that needs it.