Skip to content

Commit

Permalink
Unexpected dirty checking behavior on collections of POJOs mapped wit…
Browse files Browse the repository at this point in the history
…h JsonBinaryType #138
  • Loading branch information
vladmihalcea committed Oct 8, 2019
1 parent 921f1cc commit 527c5ae
Show file tree
Hide file tree
Showing 16 changed files with 345 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.vladmihalcea.hibernate.type.model.Location;
import com.vladmihalcea.hibernate.type.util.AbstractPostgreSQLIntegrationTest;
import com.vladmihalcea.hibernate.type.util.transaction.JPATransactionFunction;
import net.ttddyy.dsproxy.QueryCountHolder;
import org.hibernate.annotations.Type;
import org.junit.Test;

Expand Down Expand Up @@ -61,6 +62,8 @@ public Void apply(EntityManager entityManager) {
return null;
}
});

QueryCountHolder.clear();
doInJPA(new JPATransactionFunction<Void>() {
@Override
public Void apply(EntityManager entityManager) {
Expand All @@ -72,9 +75,10 @@ public Void apply(EntityManager entityManager) {
return null;
}
});
assertEquals(1, QueryCountHolder.getGrandTotal().getSelect());
assertEquals(0, QueryCountHolder.getGrandTotal().getUpdate());
}


@Entity(name = "Event")
@Table(name = "event")
public static class Event extends BaseEntity {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,22 @@ public String getCity() {
public void setCity(String city) {
this.city = city;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Location location = (Location) o;

if (country != null ? !country.equals(location.country) : location.country != null) return false;
return city != null ? city.equals(location.city) : location.city == null;
}

@Override
public int hashCode() {
int result = country != null ? country.hashCode() : 0;
result = 31 * result + (city != null ? city.hashCode() : 0);
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,25 @@ public double getPrice() {
public void setPrice(double price) {
this.price = price;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Ticket ticket = (Ticket) o;

if (Double.compare(ticket.price, price) != 0) return false;
return registrationCode != null ? registrationCode.equals(ticket.registrationCode) : ticket.registrationCode == null;
}

@Override
public int hashCode() {
int result;
long temp;
result = registrationCode != null ? registrationCode.hashCode() : 0;
temp = Double.doubleToLongBits(price);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package com.vladmihalcea.hibernate.type.util;

import com.vladmihalcea.hibernate.type.util.logging.InlineQueryLogEntryCreator;
import net.ttddyy.dsproxy.listener.ChainListener;
import net.ttddyy.dsproxy.listener.DataSourceQueryCountListener;
import net.ttddyy.dsproxy.listener.SLF4JQueryLoggingListener;
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;

import javax.sql.DataSource;

/**
Expand All @@ -9,7 +15,16 @@ public enum DataSourceProxyType {
DATA_SOURCE_PROXY {
@Override
DataSource dataSource(DataSource dataSource) {
return dataSource;
ChainListener listener = new ChainListener();
SLF4JQueryLoggingListener loggingListener = new SLF4JQueryLoggingListener();
loggingListener.setQueryLogEntryCreator(new InlineQueryLogEntryCreator());
listener.addListener(loggingListener);
listener.addListener(new DataSourceQueryCountListener());
return ProxyDataSourceBuilder
.create(dataSource)
.name(name())
.listener(listener)
.build();
}
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.vladmihalcea.hibernate.type.util.logging;

import net.ttddyy.dsproxy.ExecutionInfo;
import net.ttddyy.dsproxy.QueryInfo;
import net.ttddyy.dsproxy.listener.DefaultQueryLogEntryCreator;

import java.util.*;

/**
* @author Vlad Mihalcea
*/
public class InlineQueryLogEntryCreator extends DefaultQueryLogEntryCreator {
@Override
protected void writeParamsEntry(StringBuilder sb, ExecutionInfo execInfo, List<QueryInfo> queryInfoList) {
sb.append("Params:[");
for (QueryInfo queryInfo : queryInfoList) {
boolean firstArg = true;
for (Map<String, Object> paramMap : queryInfo.getQueryArgsList()) {

if (!firstArg) {
sb.append(", ");
} else {
firstArg = false;
}

SortedMap<String, Object> sortedParamMap = new TreeMap<String, Object>(new StringAsIntegerComparator());
sortedParamMap.putAll(paramMap);

sb.append("(");
boolean firstParam = true;
for (Map.Entry<String, Object> paramEntry : sortedParamMap.entrySet()) {
if (!firstParam) {
sb.append(", ");
} else {
firstParam = false;
}
Object parameter = paramEntry.getValue();
if (parameter != null && parameter.getClass().isArray()) {
sb.append(arrayToString(parameter));
} else {
sb.append(parameter);
}
}
sb.append(")");
}
}
sb.append("]");
}

private String arrayToString(Object object) {
if (object.getClass().isArray()) {
if (object instanceof byte[]) {
return Arrays.toString((byte[]) object);
}
if (object instanceof short[]) {
return Arrays.toString((short[]) object);
}
if (object instanceof char[]) {
return Arrays.toString((char[]) object);
}
if (object instanceof int[]) {
return Arrays.toString((int[]) object);
}
if (object instanceof long[]) {
return Arrays.toString((long[]) object);
}
if (object instanceof float[]) {
return Arrays.toString((float[]) object);
}
if (object instanceof double[]) {
return Arrays.toString((double[]) object);
}
if (object instanceof boolean[]) {
return Arrays.toString((boolean[]) object);
}
if (object instanceof Object[]) {
return Arrays.toString((Object[]) object);
}
}
throw new UnsupportedOperationException("Array type not supported: " + object.getClass());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.vladmihalcea.hibernate.type.model.Ticket;
import com.vladmihalcea.hibernate.type.util.AbstractPostgreSQLIntegrationTest;
import com.vladmihalcea.hibernate.type.util.transaction.JPATransactionFunction;
import net.ttddyy.dsproxy.QueryCountHolder;
import org.hibernate.annotations.Type;
import org.junit.Test;

Expand Down Expand Up @@ -49,6 +50,8 @@ public Void apply(EntityManager entityManager) {
return null;
}
});

QueryCountHolder.clear();
doInJPA(new JPATransactionFunction<Void>() {
@Override
public Void apply(EntityManager entityManager) {
Expand All @@ -59,9 +62,10 @@ public Void apply(EntityManager entityManager) {
return null;
}
});
assertEquals(1, QueryCountHolder.getGrandTotal().getSelect());
assertEquals(0, QueryCountHolder.getGrandTotal().getUpdate());
}


@Entity(name = "Event")
@Table(name = "event")
public static class Event extends BaseEntity {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,22 @@ public String getCity() {
public void setCity(String city) {
this.city = city;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Location location = (Location) o;

if (country != null ? !country.equals(location.country) : location.country != null) return false;
return city != null ? city.equals(location.city) : location.city == null;
}

@Override
public int hashCode() {
int result = country != null ? country.hashCode() : 0;
result = 31 * result + (city != null ? city.hashCode() : 0);
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,26 @@ public double getPrice() {
public void setPrice(double price) {
this.price = price;
}

@Override
public boolean equals(Object o) {

if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Ticket ticket = (Ticket) o;

if (Double.compare(ticket.price, price) != 0) return false;
return registrationCode != null ? registrationCode.equals(ticket.registrationCode) : ticket.registrationCode == null;
}

@Override
public int hashCode() {
int result;
long temp;
result = registrationCode != null ? registrationCode.hashCode() : 0;
temp = Double.doubleToLongBits(price);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package com.vladmihalcea.hibernate.type.util;

import com.vladmihalcea.hibernate.type.util.logging.InlineQueryLogEntryCreator;
import net.ttddyy.dsproxy.listener.ChainListener;
import net.ttddyy.dsproxy.listener.DataSourceQueryCountListener;
import net.ttddyy.dsproxy.listener.SLF4JQueryLoggingListener;
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;

import javax.sql.DataSource;

/**
Expand All @@ -9,7 +15,16 @@ public enum DataSourceProxyType {
DATA_SOURCE_PROXY {
@Override
DataSource dataSource(DataSource dataSource) {
return dataSource;
ChainListener listener = new ChainListener();
SLF4JQueryLoggingListener loggingListener = new SLF4JQueryLoggingListener();
loggingListener.setQueryLogEntryCreator(new InlineQueryLogEntryCreator());
listener.addListener(loggingListener);
listener.addListener(new DataSourceQueryCountListener());
return ProxyDataSourceBuilder
.create(dataSource)
.name(name())
.listener(listener)
.build();
}
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.vladmihalcea.hibernate.type.util.logging;

import net.ttddyy.dsproxy.ExecutionInfo;
import net.ttddyy.dsproxy.QueryInfo;
import net.ttddyy.dsproxy.listener.DefaultQueryLogEntryCreator;

import java.util.*;

/**
* @author Vlad Mihalcea
*/
public class InlineQueryLogEntryCreator extends DefaultQueryLogEntryCreator {
@Override
protected void writeParamsEntry(StringBuilder sb, ExecutionInfo execInfo, List<QueryInfo> queryInfoList) {
sb.append("Params:[");
for (QueryInfo queryInfo : queryInfoList) {
boolean firstArg = true;
for (Map<String, Object> paramMap : queryInfo.getQueryArgsList()) {

if (!firstArg) {
sb.append(", ");
} else {
firstArg = false;
}

SortedMap<String, Object> sortedParamMap = new TreeMap<String, Object>(new StringAsIntegerComparator());
sortedParamMap.putAll(paramMap);

sb.append("(");
boolean firstParam = true;
for (Map.Entry<String, Object> paramEntry : sortedParamMap.entrySet()) {
if (!firstParam) {
sb.append(", ");
} else {
firstParam = false;
}
Object parameter = paramEntry.getValue();
if (parameter != null && parameter.getClass().isArray()) {
sb.append(arrayToString(parameter));
} else {
sb.append(parameter);
}
}
sb.append(")");
}
}
sb.append("]");
}

private String arrayToString(Object object) {
if (object.getClass().isArray()) {
if (object instanceof byte[]) {
return Arrays.toString((byte[]) object);
}
if (object instanceof short[]) {
return Arrays.toString((short[]) object);
}
if (object instanceof char[]) {
return Arrays.toString((char[]) object);
}
if (object instanceof int[]) {
return Arrays.toString((int[]) object);
}
if (object instanceof long[]) {
return Arrays.toString((long[]) object);
}
if (object instanceof float[]) {
return Arrays.toString((float[]) object);
}
if (object instanceof double[]) {
return Arrays.toString((double[]) object);
}
if (object instanceof boolean[]) {
return Arrays.toString((boolean[]) object);
}
if (object instanceof Object[]) {
return Arrays.toString((Object[]) object);
}
}
throw new UnsupportedOperationException("Array type not supported: " + object.getClass());
}
}
Loading

0 comments on commit 527c5ae

Please sign in to comment.