Reputation: 13666
I use jOOQ 3.8.4 and Postgres 9.5. I have a complex schema. Actually, when I do a simple select, like:
create.selectFrom(ARTICLE_VIEW)
.orderBy(ARTICLE_VIEW.AV_CREATION_DATE
.desc()).limit(4).fetch();
I get:
java.lang.StackOverflowError
org.jooq.Converters$1.<init>(Converters.java:67)
org.jooq.Converters.identity(Converters.java:67)
org.jooq.impl.DefaultBinding.pgFromString(DefaultBinding.java:2041)
org.jooq.impl.DefaultBinding.pgFromString(DefaultBinding.java:2130)
org.jooq.impl.DefaultBinding.pgFromString(DefaultBinding.java:2041)
org.jooq.impl.DefaultBinding.pgFromString(DefaultBinding.java:2130)
org.jooq.impl.DefaultBinding.pgFromString(DefaultBinding.java:2041)
and more (funny, it is my first StackOverflowException
)!
I activated the DEBUG logging mode, and I copied the select and execute it in PGAdmin. It works. There should be something wrong in jOOQ, but I do not know how to provide useful information. Posting the schema I use would be madness, it requires dozens of tables. Any hint on how to proceed?
UPDATE
Here follows the record class
/**
* This class is generated by jOOQ
*/
package com.model.jooq.shop.tables.records;
import com.google.gson.JsonElement;
import com.model.jooq.shop.enums.BrandCountry;
import com.model.jooq.shop.enums.Color;
import com.model.jooq.shop.enums.Discount;
import com.model.jooq.shop.enums.Season;
import com.model.jooq.shop.tables.ArticleView;
import com.model.jooq.shop.udt.records.ArticleSimpleTypeRecord;
import com.model.jooq.shop.udt.records.CategoryTypeRecord;
import com.model.jooq.shop.udt.records.LocalizedMoneyRecord;
import com.model.jooq.shop.udt.records.SameModelArticleTypeRecord;
import java.io.Serializable;
import java.sql.Timestamp;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.validation.constraints.Size;
import org.jooq.impl.TableRecordImpl;
/**
* This class is generated by jOOQ.
*/
@SuppressWarnings({ "all", "unchecked", "rawtypes" })
@Entity
@Table(name = "article_view", schema = "shop")
public class ArticleViewRecord extends TableRecordImpl<ArticleViewRecord> implements Serializable, Cloneable {
private static final long serialVersionUID = -1404712730;
/**
* Setter for <code>shop.article_view.av_article_id</code>.
*/
public ArticleViewRecord setArticleId(Long value) {
set(0, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_article_id</code>.
*/
@Column(name = "av_article_id", precision = 64)
public Long getArticleId() {
return (Long) get(0);
}
/**
* Setter for <code>shop.article_view.av_article_model_id</code>.
*/
public ArticleViewRecord setArticleModelId(Long value) {
set(1, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_article_model_id</code>.
*/
@Column(name = "av_article_model_id", precision = 64)
public Long getArticleModelId() {
return (Long) get(1);
}
/**
* Setter for <code>shop.article_view.av_article_name</code>.
*/
public ArticleViewRecord setArticleName(String value) {
set(2, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_article_name</code>.
*/
@Column(name = "av_article_name", length = 25)
@Size(max = 25)
public String getArticleName() {
return (String) get(2);
}
/**
* Setter for <code>shop.article_view.av_article_name_for_url</code>.
*/
public ArticleViewRecord setArticleNameForUrl(String value) {
set(3, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_article_name_for_url</code>.
*/
@Column(name = "av_article_name_for_url", length = 25)
@Size(max = 25)
public String getArticleNameForUrl() {
return (String) get(3);
}
/**
* Setter for <code>shop.article_view.av_article_season</code>.
*/
public ArticleViewRecord setArticleSeason(Season value) {
set(4, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_article_season</code>.
*/
@Column(name = "av_article_season")
public Season getArticleSeason() {
return (Season) get(4);
}
/**
* Setter for <code>shop.article_view.av_article_year</code>.
*/
public ArticleViewRecord setArticleYear(Short value) {
set(5, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_article_year</code>.
*/
@Column(name = "av_article_year", precision = 16)
public Short getArticleYear() {
return (Short) get(5);
}
/**
* Setter for <code>shop.article_view.av_article_standard_size_designation</code>.
*/
public ArticleViewRecord setArticleStandardSizeDesignation(Boolean value) {
set(6, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_article_standard_size_designation</code>.
*/
@Column(name = "av_article_standard_size_designation")
public Boolean getArticleStandardSizeDesignation() {
return (Boolean) get(6);
}
/**
* Setter for <code>shop.article_view.av_article_ean13</code>.
*/
public ArticleViewRecord setArticleEan13(String value) {
set(7, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_article_ean13</code>.
*/
@Column(name = "av_article_ean13", length = 13)
@Size(max = 13)
public String getArticleEan13() {
return (String) get(7);
}
/**
* Setter for <code>shop.article_view.av_article_config_sku</code>.
*/
public ArticleViewRecord setArticleConfigSku(String value) {
set(8, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_article_config_sku</code>.
*/
@Column(name = "av_article_config_sku", length = 12)
@Size(max = 12)
public String getArticleConfigSku() {
return (String) get(8);
}
/**
* Setter for <code>shop.article_view.av_article_features</code>.
*/
public ArticleViewRecord setArticleFeatures(JsonElement value) {
set(9, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_article_features</code>.
*/
@Column(name = "av_article_features")
public JsonElement getArticleFeatures() {
return (JsonElement) get(9);
}
/**
* Setter for <code>shop.article_view.av_article_color</code>.
*/
public ArticleViewRecord setArticleColor(Color value) {
set(10, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_article_color</code>.
*/
@Column(name = "av_article_color")
public Color getArticleColor() {
return (Color) get(10);
}
/**
* Setter for <code>shop.article_view.av_article_color2</code>.
*/
public ArticleViewRecord setArticleColor2(Color value) {
set(11, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_article_color2</code>.
*/
@Column(name = "av_article_color2")
public Color getArticleColor2() {
return (Color) get(11);
}
/**
* Setter for <code>shop.article_view.av_article_color3</code>.
*/
public ArticleViewRecord setArticleColor3(Color value) {
set(12, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_article_color3</code>.
*/
@Column(name = "av_article_color3")
public Color getArticleColor3() {
return (Color) get(12);
}
/**
* Setter for <code>shop.article_view.av_article_color_detail</code>.
*/
public ArticleViewRecord setArticleColorDetail(JsonElement value) {
set(13, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_article_color_detail</code>.
*/
@Column(name = "av_article_color_detail")
public JsonElement getArticleColorDetail() {
return (JsonElement) get(13);
}
/**
* Setter for <code>shop.article_view.av_article_paid_price</code>.
*/
public ArticleViewRecord setArticlePaidPrice(LocalizedMoneyRecord[] value) {
set(14, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_article_paid_price</code>.
*/
@Column(name = "av_article_paid_price")
public LocalizedMoneyRecord[] getArticlePaidPrice() {
return (LocalizedMoneyRecord[]) get(14);
}
/**
* Setter for <code>shop.article_view.av_article_price</code>.
*/
public ArticleViewRecord setArticlePrice(LocalizedMoneyRecord[] value) {
set(15, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_article_price</code>.
*/
@Column(name = "av_article_price")
public LocalizedMoneyRecord[] getArticlePrice() {
return (LocalizedMoneyRecord[]) get(15);
}
/**
* Setter for <code>shop.article_view.av_article_image_filenames</code>.
*/
public ArticleViewRecord setArticleImageFilenames(String[] value) {
set(16, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_article_image_filenames</code>.
*/
@Column(name = "av_article_image_filenames")
public String[] getArticleImageFilenames() {
return (String[]) get(16);
}
/**
* Setter for <code>shop.article_view.av_article_active_from</code>.
*/
public ArticleViewRecord setArticleActiveFrom(Timestamp value) {
set(17, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_article_active_from</code>.
*/
@Column(name = "av_article_active_from")
public Timestamp getArticleActiveFrom() {
return (Timestamp) get(17);
}
/**
* Setter for <code>shop.article_view.av_article_discount</code>.
*/
public ArticleViewRecord setArticleDiscount(Discount value) {
set(18, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_article_discount</code>.
*/
@Column(name = "av_article_discount")
public Discount getArticleDiscount() {
return (Discount) get(18);
}
/**
* Setter for <code>shop.article_view.av_brand_id</code>.
*/
public ArticleViewRecord setBrandId(Short value) {
set(19, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_brand_id</code>.
*/
@Column(name = "av_brand_id", precision = 16)
public Short getBrandId() {
return (Short) get(19);
}
/**
* Setter for <code>shop.article_view.av_brand_name</code>.
*/
public ArticleViewRecord setBrandName(String value) {
set(20, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_brand_name</code>.
*/
@Column(name = "av_brand_name", length = 25)
@Size(max = 25)
public String getBrandName() {
return (String) get(20);
}
/**
* Setter for <code>shop.article_view.av_brand_name_for_url</code>.
*/
public ArticleViewRecord setBrandNameForUrl(String value) {
set(21, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_brand_name_for_url</code>.
*/
@Column(name = "av_brand_name_for_url", length = 25)
@Size(max = 25)
public String getBrandNameForUrl() {
return (String) get(21);
}
/**
* Setter for <code>shop.article_view.av_brand_country</code>.
*/
public ArticleViewRecord setBrandCountry(BrandCountry value) {
set(22, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_brand_country</code>.
*/
@Column(name = "av_brand_country")
public BrandCountry getBrandCountry() {
return (BrandCountry) get(22);
}
/**
* Setter for <code>shop.article_view.av_brand_logo_url</code>.
*/
public ArticleViewRecord setBrandLogoUrl(String value) {
set(23, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_brand_logo_url</code>.
*/
@Column(name = "av_brand_logo_url", length = 250)
@Size(max = 250)
public String getBrandLogoUrl() {
return (String) get(23);
}
/**
* Setter for <code>shop.article_view.av_brand_facts</code>.
*/
public ArticleViewRecord setBrandFacts(JsonElement value) {
set(24, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_brand_facts</code>.
*/
@Column(name = "av_brand_facts")
public JsonElement getBrandFacts() {
return (JsonElement) get(24);
}
/**
* Setter for <code>shop.article_view.av_commodity_group_id</code>.
*/
public ArticleViewRecord setCommodityGroupId(Long value) {
set(25, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_commodity_group_id</code>.
*/
@Column(name = "av_commodity_group_id", precision = 64)
public Long getCommodityGroupId() {
return (Long) get(25);
}
/**
* Setter for <code>shop.article_view.av_commodity_group_name</code>.
*/
public ArticleViewRecord setCommodityGroupName(String value) {
set(26, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_commodity_group_name</code>.
*/
@Column(name = "av_commodity_group_name", length = 25)
@Size(max = 25)
public String getCommodityGroupName() {
return (String) get(26);
}
/**
* Setter for <code>shop.article_view.av_commodity_group_name_for_url</code>.
*/
public ArticleViewRecord setCommodityGroupNameForUrl(String value) {
set(27, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_commodity_group_name_for_url</code>.
*/
@Column(name = "av_commodity_group_name_for_url", length = 25)
@Size(max = 25)
public String getCommodityGroupNameForUrl() {
return (String) get(27);
}
/**
* Setter for <code>shop.article_view.av_categories</code>.
*/
public ArticleViewRecord setCategories(CategoryTypeRecord[] value) {
set(28, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_categories</code>.
*/
@Column(name = "av_categories")
public CategoryTypeRecord[] getCategories() {
return (CategoryTypeRecord[]) get(28);
}
/**
* Setter for <code>shop.article_view.av_sizes</code>.
*/
public ArticleViewRecord setSizes(ArticleSimpleTypeRecord[] value) {
set(29, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_sizes</code>.
*/
@Column(name = "av_sizes")
public ArticleSimpleTypeRecord[] getSizes() {
return (ArticleSimpleTypeRecord[]) get(29);
}
/**
* Setter for <code>shop.article_view.av_all_model_colors</code>.
*/
public ArticleViewRecord setAllModelColors(SameModelArticleTypeRecord[] value) {
set(30, value);
return this;
}
/**
* Getter for <code>shop.article_view.av_all_model_colors</code>.
*/
@Column(name = "av_all_model_colors")
public SameModelArticleTypeRecord[] getAllModelColors() {
return (SameModelArticleTypeRecord[]) get(30);
}
// -------------------------------------------------------------------------
// Constructors
// -------------------------------------------------------------------------
/**
* Create a detached ArticleViewRecord
*/
public ArticleViewRecord() {
super(ArticleView.ACTIVE_ARTICLE_VIEW);
}
/**
* Create a detached, initialised ArticleViewRecord
*/
public ArticleViewRecord(Long article_id, Long article_model_id, String article_name, String article_name_for_url, Season article_season, Short article_year, Boolean article_standard_size_designation, String article_ean13, String article_config_sku, JsonElement article_features, Color article_color, Color article_color2, Color article_color3, JsonElement article_color_detail, LocalizedMoneyRecord[] article_paid_price, LocalizedMoneyRecord[] article_price, String[] article_image_filenames, Timestamp article_active_from, Discount article_discount, Short brand_id, String brand_name, String brand_name_for_url, BrandCountry brand_country, String brand_logo_url, JsonElement brand_facts, Long commodity_group_id, String commodity_group_name, String commodity_group_name_for_url, CategoryTypeRecord[] categories, ArticleSimpleTypeRecord[] sizes, SameModelArticleTypeRecord[] all_model_colors) {
super(ArticleView.ACTIVE_ARTICLE_VIEW);
set(0, article_id);
set(1, article_model_id);
set(2, article_name);
set(3, article_name_for_url);
set(4, article_season);
set(5, article_year);
set(6, article_standard_size_designation);
set(7, article_ean13);
set(8, article_config_sku);
set(9, article_features);
set(10, article_color);
set(11, article_color2);
set(12, article_color3);
set(13, article_color_detail);
set(14, article_paid_price);
set(15, article_price);
set(16, article_image_filenames);
set(17, article_active_from);
set(18, article_discount);
set(19, brand_id);
set(20, brand_name);
set(21, brand_name_for_url);
set(22, brand_country);
set(23, brand_logo_url);
set(24, brand_facts);
set(25, commodity_group_id);
set(26, commodity_group_name);
set(27, commodity_group_name_for_url);
set(28, categories);
set(29, sizes);
set(30, all_model_colors);
}
}
Possible source of the issue
I debugged following the link from Andrew Rueckert, but it seems to be that the issue is in jOOQ. It does not handle properly types inside types.
The view contains a ArticleSimpleTypeRecord
that is a PostgreSQL type. It has a type internally.
The steps executed in class DefaultBinding
are:
method pgFromString
is called with the default converter for the ArticleSimpleTypeRecord
. This imply that the following instruction is called:
else if (Record.class.isAssignableFrom(type)) { return (T) pgNewRecord(type, null, string); }
method pgNewRecord
tries to create a record from the given object by calling the following method:
public Record operate(Record record) {
List<String> values = PostgresUtils.toPGObject(object.toString());
Row row = record.fieldsRow();
for (int i = 0; i < row.size(); i++) {
pgSetValue(record, row.field(i), values.get(i));
}
return record;
}
which will set the values into the record using the method pgSetValue
and the values from the object
.
When it comes to set the value for the json
value jOOQ calls the method pgSetValue(Record record, Field<T> field, String value)
which calls the method pgFromString
using the converter for the field (i.e. the PostgresJSONGsonBinding
JSON converter I found on jOOQ website). The problem comes inside method pgFromString
.
Inside pgFromString
, the line Class<T> type = converter.toType()
returns com.google.gson.JsonElement
, which is not binded by any default value so it goes to line:
else {
Converter<Object, T> c = (Converter<Object, T>) converter;
return c.from(pgFromString(c.fromType(), string));
}
Here comes the issue, because the json converter should convert the value into a json starting from the object returned by pgFromString(c.fromType(), string)
, but since c.fromType()
returns Object
and there is no default binding for Object in jOOQ is goes again to the default case and again and again and we have the StackOverflowException
.
I had a look at the changes in that class, and seems that the current master has fixed the issue. There is now:
else if (type == Object.class) {
return (T) string;
}
Then, I have to wait for the next jOOQ minor release. I hope it comes soon.
Upvotes: 1
Views: 743
Reputation: 5215
Have you registered a custom binding for JsonElement? We use Gson types as well, and had to do the following:
pom.xml (abbreviated)
<plugin>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen-maven</artifactId>
<version>${jooq.version}</version>
<configuration>
<generator>
<database>
<forcedTypes>
<forcedType>
<name>GsonJson</name>
<userType>com.google.gson.JsonElement</userType>
<binding>com.mycompany.dao.bindings.GsonJsonBinding</binding>
<types>json</types>
</forcedType>
</forcedTypes>
</database>
</generator>
</configuration>
</plugin>
GsonJsonBinding.java
public class GsonJsonBinding extends GenericStringlikeBinding<JsonElement> {
public GsonJsonBinding() {
super("json", new JsonConverter());
}
}
JsonConverter.java
public class JsonConverter implements Converter<Object, JsonElement> {
private static final Gson gson = new Gson();
@Override
public JsonElement from(Object t) {
return t == null ? null : gson.fromJson("" + t, JsonElement.class);
}
@Override
public Object to(JsonElement u) {
return u == null || u == JsonNull.INSTANCE ? null : gson.toJson(u);
}
@Override
public Class<Object> fromType() {
return Object.class;
}
@Override
public Class<JsonElement> toType() {
return JsonElement.class;
}
}
Upvotes: -1