mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-10-21 11:09:17 +00:00
Scalar type querybeans generics error (#2082)
* Add failing test case for generic querybeans Types with generics arguments have not been processed correctly, they will lose their generics. This is not critical in Java, as the language has to be backwards compatible with Java 1.4, but will still become highlighted as a warning in all common IDEs. In Kotlin however, it's not a warning but a compile error. * Fix problem with generics in scalar type arg This fixes the issue introduced with ScalarType aware querybeans.
This commit is contained in:
@@ -48,14 +48,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddlgen</artifactId>
|
||||
<version>12.5.0</version>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>querybean-generator</artifactId>
|
||||
<version>12.5.0</version>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@ import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.example.domain.otherpackage.GenericType;
|
||||
import org.example.domain.otherpackage.GenericTypeArgument;
|
||||
|
||||
/**
|
||||
* Address entity bean.
|
||||
*/
|
||||
@@ -24,8 +27,10 @@ public class Address extends BaseModel {
|
||||
@ManyToOne
|
||||
Country country;
|
||||
|
||||
GenericType<GenericTypeArgument> metadata;
|
||||
|
||||
/**
|
||||
* Create a copy of the address. Used to provide a 'snapshot' of
|
||||
* Create a copy of the address. Used to provide a 'snapshot' of
|
||||
* the shippingAddress for a give order.
|
||||
*/
|
||||
public Address createCopy() {
|
||||
@@ -36,7 +41,7 @@ public class Address extends BaseModel {
|
||||
copy.setCountry(country);
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
return id + " " + line1 + " " + line2 + " " + city + " " + country;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.example.domain.otherpackage;
|
||||
|
||||
public class GenericType<T> {
|
||||
private T data;
|
||||
|
||||
public GenericType(final T data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(final T data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.example.domain.otherpackage;
|
||||
|
||||
public enum GenericTypeArgument {
|
||||
FOO,
|
||||
BAR;
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package org.example.domain.otherpackage;
|
||||
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Converter;
|
||||
|
||||
@Converter
|
||||
public class GenericTypeAttributeConverter implements AttributeConverter<GenericType<GenericTypeArgument>, String> {
|
||||
@Override
|
||||
public String convertToDatabaseColumn(final GenericType<GenericTypeArgument> attribute) {
|
||||
return attribute.getData().name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericType<GenericTypeArgument> convertToEntityAttribute(final String dbData) {
|
||||
return new GenericType<>(GenericTypeArgument.valueOf(dbData));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
@@ -9,6 +10,10 @@
|
||||
|
||||
<artifactId>kotlin-querybean-generator</artifactId>
|
||||
|
||||
<properties>
|
||||
<kotlin.version>1.4.10</kotlin.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
@@ -17,16 +22,100 @@
|
||||
<version>3.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-test</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddlgen</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
<version>1.1.0.Final</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
<build>
|
||||
<testSourceDirectory>src/test/kotlin</testSourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test-compile</id>
|
||||
<phase>test-compile</phase>
|
||||
<goals>
|
||||
<goal>test-compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-kapt</id>
|
||||
<goals>
|
||||
<goal>test-kapt</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sourceDirs>
|
||||
<sourceDir>src/test/kotlin</sourceDir>
|
||||
</sourceDirs>
|
||||
<annotationProcessorPaths>
|
||||
<annotationProcessorPath>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>kotlin-querybean-generator</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</annotationProcessorPath>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<jvmTarget>1.8</jvmTarget>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-testCompile</id>
|
||||
<phase>none</phase>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>java-test-compile</id>
|
||||
<phase>test-compile</phase>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
@@ -34,6 +123,25 @@
|
||||
<compilerArgument>-proc:none</compilerArgument>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>12.5.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
<phase>process-test-classes</phase>
|
||||
<configuration>
|
||||
<transformArgs>debug=1</transformArgs>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>testEnhance</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
+2
-2
@@ -333,9 +333,9 @@ class ProcessingContext implements Constants {
|
||||
return result;
|
||||
} else {
|
||||
if (typeInstanceOf(typeMirror, "java.lang.Comparable")) {
|
||||
return new PropertyTypeScalarComparable(typeDef(typeMirror));
|
||||
return new PropertyTypeScalarComparable(typeMirror.toString());
|
||||
} else {
|
||||
return new PropertyTypeScalar(typeDef(typeMirror));
|
||||
return new PropertyTypeScalar(typeMirror.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-10
@@ -1,17 +1,18 @@
|
||||
package io.ebean.querybean.generator;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Property type for associated beans (OneToMany, ManyToOne etc).
|
||||
* Property type for fields handled by ScalarTypes
|
||||
*/
|
||||
class PropertyTypeScalar extends PropertyType {
|
||||
|
||||
/**
|
||||
* The package name for this associated query bean.
|
||||
*/
|
||||
private final String assocPackage;
|
||||
private final String attributeSimpleName;
|
||||
private final Set<String> assocImports;
|
||||
private final String attributeCompleteSignature;
|
||||
|
||||
/**
|
||||
* Construct given the associated bean type name and package.
|
||||
@@ -19,20 +20,26 @@ class PropertyTypeScalar extends PropertyType {
|
||||
* @param attributeClass the type in the database bean that will be serialized via ScalarType
|
||||
*/
|
||||
PropertyTypeScalar(String attributeClass) {
|
||||
super("PScalar");
|
||||
int split = attributeClass.lastIndexOf('.');
|
||||
this.assocPackage = attributeClass.substring(0, split);
|
||||
this.attributeSimpleName = attributeClass.substring(split + 1);
|
||||
this("PScalar", attributeClass);
|
||||
}
|
||||
|
||||
protected PropertyTypeScalar(String propertyType, String attributeClass) {
|
||||
super(propertyType);
|
||||
|
||||
final Entry<String, Set<String>> signature = Split.genericsSplit(attributeClass);
|
||||
|
||||
this.attributeCompleteSignature = signature.getKey();
|
||||
this.assocImports = signature.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
String getTypeDefn(String shortName, boolean assoc) {
|
||||
if (assoc) {
|
||||
// PScalarType<R, PhoneNumber>
|
||||
return "PScalar<R, " + attributeSimpleName + ">";
|
||||
return propertyType + "<R, " + attributeCompleteSignature + ">";
|
||||
} else {
|
||||
// PScalarType<QCustomer, PhoneNumber>
|
||||
return "PScalar<Q" + shortName + ", " + attributeSimpleName + ">";
|
||||
return propertyType + "<Q" + shortName + ", " + attributeCompleteSignature + ">";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +49,7 @@ class PropertyTypeScalar extends PropertyType {
|
||||
@Override
|
||||
void addImports(Set<String> allImports) {
|
||||
super.addImports(allImports);
|
||||
allImports.add(assocPackage + "." + attributeSimpleName);
|
||||
allImports.addAll(assocImports);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-35
@@ -1,17 +1,9 @@
|
||||
package io.ebean.querybean.generator;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Property type for associated beans (OneToMany, ManyToOne etc).
|
||||
* Property type for fields handled by ScalarTypes
|
||||
*/
|
||||
class PropertyTypeScalarComparable extends PropertyType {
|
||||
|
||||
/**
|
||||
* The package name for this associated query bean.
|
||||
*/
|
||||
private final String assocPackage;
|
||||
private final String attributeSimpleName;
|
||||
class PropertyTypeScalarComparable extends PropertyTypeScalar {
|
||||
|
||||
/**
|
||||
* Construct given the associated bean type name and package.
|
||||
@@ -19,30 +11,6 @@ class PropertyTypeScalarComparable extends PropertyType {
|
||||
* @param attributeClass the type in the database bean that will be serialized via ScalarType
|
||||
*/
|
||||
PropertyTypeScalarComparable(String attributeClass) {
|
||||
super("PScalarComparable");
|
||||
int split = attributeClass.lastIndexOf('.');
|
||||
this.assocPackage = attributeClass.substring(0, split);
|
||||
this.attributeSimpleName = attributeClass.substring(split + 1);
|
||||
super("PScalarComparable", attributeClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getTypeDefn(String shortName, boolean assoc) {
|
||||
if (assoc) {
|
||||
// PScalarType<R, PhoneNumber>
|
||||
return "PScalarComparable<R, " + attributeSimpleName + ">";
|
||||
} else {
|
||||
// PScalarType<QCustomer, PhoneNumber>
|
||||
return "PScalarComparable<Q" + shortName + ", " + attributeSimpleName + ">";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* All required imports to the allImports set.
|
||||
*/
|
||||
@Override
|
||||
void addImports(Set<String> allImports) {
|
||||
super.addImports(allImports);
|
||||
allImports.add(assocPackage + "." + attributeSimpleName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package io.ebean.querybean.generator;
|
||||
|
||||
import java.util.AbstractMap.SimpleEntry;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Helper for splitting package and class name.
|
||||
*/
|
||||
@@ -41,4 +47,20 @@ class Split {
|
||||
return fullType;
|
||||
}
|
||||
|
||||
static Entry<String, Set<String>> genericsSplit(String signature) {
|
||||
StringBuilder simpleSignature = new StringBuilder();
|
||||
final StringTokenizer tokenizer = new StringTokenizer(signature, ",<> ", true);
|
||||
|
||||
Set<String> assocImports = new HashSet<>();
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
final String token = tokenizer.nextToken();
|
||||
if (token.length() == 1 && ",<> ".indexOf(token.charAt(0)) >= 0) {
|
||||
simpleSignature.append(token);
|
||||
} else {
|
||||
simpleSignature.append(Split.shortName(token));
|
||||
assocImports.add(token);
|
||||
}
|
||||
}
|
||||
return new SimpleEntry<>(simpleSignature.toString(), assocImports);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
package io.ebean.querybean.generator;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNull;
|
||||
|
||||
public class SplitTest {
|
||||
|
||||
@Test
|
||||
public void trimType() {
|
||||
assertEquals(Split.trimType("com.foo.domain.Customer"), "com.foo.domain.Customer");
|
||||
assertEquals(Split.trimType("? extends com.foo.domain.Customer"), "com.foo.domain.Customer");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shortName() {
|
||||
assertEquals(Split.shortName("com.foo.domain.Customer"), "Customer");
|
||||
assertEquals(Split.shortName("Customer"), "Customer");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void split_normal() {
|
||||
|
||||
String[] split = Split.split("com.foo.domain.Customer");
|
||||
|
||||
assertEquals(split[0], "com.foo.domain");
|
||||
assertEquals(split[1], "Customer");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void split_noPackage() {
|
||||
|
||||
String[] split = Split.split("Customer");
|
||||
|
||||
assertNull(split[0]);
|
||||
assertEquals(split[1], "Customer");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package io.ebean.querybean.generator
|
||||
|
||||
import org.testng.Assert.assertEquals
|
||||
import org.testng.Assert.assertNull
|
||||
import org.testng.annotations.Test
|
||||
import java.lang.Exception
|
||||
import java.util.Arrays
|
||||
import java.util.HashSet
|
||||
|
||||
class SplitTest {
|
||||
@Test
|
||||
fun trimType() {
|
||||
assertEquals(Split.trimType("com.foo.domain.Customer"), "com.foo.domain.Customer")
|
||||
assertEquals(Split.trimType("? extends com.foo.domain.Customer"), "com.foo.domain.Customer")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shortName() {
|
||||
assertEquals(Split.shortName("com.foo.domain.Customer"), "Customer")
|
||||
assertEquals(Split.shortName("Customer"), "Customer")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun split_normal() {
|
||||
val split = Split.split("com.foo.domain.Customer")
|
||||
assertEquals(split[0], "com.foo.domain")
|
||||
assertEquals(split[1], "Customer")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun split_noPackage() {
|
||||
val split = Split.split("Customer")
|
||||
assertNull(split[0])
|
||||
assertEquals(split[1], "Customer")
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun split_generics() {
|
||||
assertEquals("Foo<Bar, XFoo<XBar>>", Split.genericsSplit("com.Foo<com.Bar, org.XFoo<org.XBar>>").key)
|
||||
assertEquals(
|
||||
HashSet(Arrays.asList("com.Foo", "com.Bar", "org.XFoo", "org.XBar")),
|
||||
Split.genericsSplit("com.Foo<com.Bar, org.XFoo<org.XBar>>").value
|
||||
)
|
||||
assertEquals("Foo", Split.genericsSplit("com.bar.Foo").key)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.example.domain;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.example.otherpackage.GenericType;
|
||||
import org.example.otherpackage.GenericTypeArgument;
|
||||
|
||||
/**
|
||||
* Address entity bean.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "o_address")
|
||||
class Address(
|
||||
@Size(max = 100)
|
||||
var line1: String,
|
||||
@Size(max = 100)
|
||||
var line2: String,
|
||||
@Size(max = 100)
|
||||
var city: String,
|
||||
// Dummy metadata field just to test generation
|
||||
val metadata: GenericType<GenericTypeArgument>
|
||||
) : BaseModel()
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.example.domain;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.Version;
|
||||
|
||||
import io.ebean.Model;
|
||||
import io.ebean.annotation.WhenCreated;
|
||||
import io.ebean.annotation.WhenModified;
|
||||
|
||||
@MappedSuperclass
|
||||
abstract class BaseModel : Model() {
|
||||
@Id
|
||||
val id: Long? = null
|
||||
|
||||
@Version
|
||||
val version: Int = 0
|
||||
|
||||
@WhenCreated
|
||||
val whenCreated: Instant? = null
|
||||
|
||||
@WhenModified
|
||||
val whenModified: Instant? = null
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package org.example.otherpackage
|
||||
|
||||
interface Email<T> : Comparable<T>
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.example.otherpackage
|
||||
|
||||
class GenericType<T>(
|
||||
val data: T
|
||||
)
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package org.example.otherpackage
|
||||
|
||||
enum class GenericTypeArgument {
|
||||
FOO,
|
||||
BAR,
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package org.example.otherpackage
|
||||
|
||||
import javax.persistence.AttributeConverter
|
||||
import javax.persistence.Converter
|
||||
|
||||
@Converter
|
||||
class GenericTypeAttributeConverter : AttributeConverter<GenericType<GenericTypeArgument>, String> {
|
||||
override fun convertToDatabaseColumn(attribute: GenericType<GenericTypeArgument>): String {
|
||||
return attribute.data.name
|
||||
}
|
||||
|
||||
override fun convertToEntityAttribute(dbData: String): GenericType<GenericTypeArgument> {
|
||||
return GenericType(GenericTypeArgument.valueOf(dbData))
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package org.example.otherpackage
|
||||
|
||||
import javax.persistence.AttributeConverter
|
||||
import javax.persistence.Converter
|
||||
|
||||
@Converter
|
||||
class PhoneAttributeConverter : AttributeConverter<PhoneNumber, String> {
|
||||
override fun convertToDatabaseColumn(attribute: PhoneNumber): String {
|
||||
return attribute.msisdn
|
||||
}
|
||||
|
||||
override fun convertToEntityAttribute(dbData: String): PhoneNumber {
|
||||
return PhoneNumber(dbData)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.example.otherpackage
|
||||
|
||||
class PhoneNumber(
|
||||
val msisdn: String
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.example.otherpackage
|
||||
|
||||
class ValidEmail(
|
||||
val emailAddress: String
|
||||
) : Email<ValidEmail> {
|
||||
override fun compareTo(other: ValidEmail): Int {
|
||||
return emailAddress.compareTo(other.emailAddress)
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package org.example.otherpackage
|
||||
|
||||
import javax.persistence.AttributeConverter
|
||||
import javax.persistence.Converter
|
||||
|
||||
@Converter
|
||||
class ValidEmailAttributeConverter : AttributeConverter<ValidEmail, String> {
|
||||
override fun convertToDatabaseColumn(attribute: ValidEmail): String {
|
||||
return attribute.emailAddress
|
||||
}
|
||||
|
||||
override fun convertToEntityAttribute(dbData: String): ValidEmail {
|
||||
return ValidEmail(dbData)
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -298,9 +298,9 @@ class ProcessingContext implements Constants {
|
||||
return result;
|
||||
} else {
|
||||
if (typeInstanceOf(typeMirror, "java.lang.Comparable")) {
|
||||
return new PropertyTypeScalarComparable(typeDef(typeMirror));
|
||||
return new PropertyTypeScalarComparable(typeMirror.toString());
|
||||
} else {
|
||||
return new PropertyTypeScalar(typeDef(typeMirror));
|
||||
return new PropertyTypeScalar(typeMirror.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-12
@@ -1,17 +1,17 @@
|
||||
package io.ebean.querybean.generator;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Property type for associated beans (OneToMany, ManyToOne etc).
|
||||
* Property type for fields handled by ScalarTypes
|
||||
*/
|
||||
class PropertyTypeScalar extends PropertyType {
|
||||
|
||||
/**
|
||||
* The package name for this associated query bean.
|
||||
*/
|
||||
private final String assocPackage;
|
||||
private final String attributeSimpleName;
|
||||
private final Set<String> assocImports;
|
||||
private final String attributeCompleteSignature;
|
||||
|
||||
/**
|
||||
* Construct given the associated bean type name and package.
|
||||
@@ -19,20 +19,26 @@ class PropertyTypeScalar extends PropertyType {
|
||||
* @param attributeClass the type in the database bean that will be serialized via ScalarType
|
||||
*/
|
||||
PropertyTypeScalar(String attributeClass) {
|
||||
super("PScalar");
|
||||
int split = attributeClass.lastIndexOf('.');
|
||||
this.assocPackage = attributeClass.substring(0, split);
|
||||
this.attributeSimpleName = attributeClass.substring(split + 1);
|
||||
this("PScalar", attributeClass);
|
||||
}
|
||||
|
||||
protected PropertyTypeScalar(String propertyType, String attributeClass) {
|
||||
super(propertyType);
|
||||
|
||||
final Entry<String, Set<String>> signature = Split.genericsSplit(attributeClass);
|
||||
|
||||
this.attributeCompleteSignature = signature.getKey();
|
||||
this.assocImports = signature.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
String getTypeDefn(String shortName, boolean assoc) {
|
||||
if (assoc) {
|
||||
// PScalarType<R, PhoneNumber>
|
||||
return "PScalar<R, " + attributeSimpleName + ">";
|
||||
return propertyType + "<R, " + attributeCompleteSignature + ">";
|
||||
} else {
|
||||
// PScalarType<QCustomer, PhoneNumber>
|
||||
return "PScalar<Q" + shortName + ", " + attributeSimpleName + ">";
|
||||
return propertyType + "<Q" + shortName + ", " + attributeCompleteSignature + ">";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +48,6 @@ class PropertyTypeScalar extends PropertyType {
|
||||
@Override
|
||||
void addImports(Set<String> allImports) {
|
||||
super.addImports(allImports);
|
||||
allImports.add(assocPackage + "." + attributeSimpleName);
|
||||
allImports.addAll(assocImports);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-34
@@ -1,17 +1,9 @@
|
||||
package io.ebean.querybean.generator;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Property type for associated beans (OneToMany, ManyToOne etc).
|
||||
*/
|
||||
class PropertyTypeScalarComparable extends PropertyType {
|
||||
|
||||
/**
|
||||
* The package name for this associated query bean.
|
||||
*/
|
||||
private final String assocPackage;
|
||||
private final String attributeSimpleName;
|
||||
class PropertyTypeScalarComparable extends PropertyTypeScalar {
|
||||
|
||||
/**
|
||||
* Construct given the associated bean type name and package.
|
||||
@@ -19,30 +11,6 @@ class PropertyTypeScalarComparable extends PropertyType {
|
||||
* @param attributeClass the type in the database bean that will be serialized via ScalarType
|
||||
*/
|
||||
PropertyTypeScalarComparable(String attributeClass) {
|
||||
super("PScalarComparable");
|
||||
int split = attributeClass.lastIndexOf('.');
|
||||
this.assocPackage = attributeClass.substring(0, split);
|
||||
this.attributeSimpleName = attributeClass.substring(split + 1);
|
||||
super("PScalarComparable", attributeClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getTypeDefn(String shortName, boolean assoc) {
|
||||
if (assoc) {
|
||||
// PScalarType<R, PhoneNumber>
|
||||
return "PScalarComparable<R, " + attributeSimpleName + ">";
|
||||
} else {
|
||||
// PScalarType<QCustomer, PhoneNumber>
|
||||
return "PScalarComparable<Q" + shortName + ", " + attributeSimpleName + ">";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* All required imports to the allImports set.
|
||||
*/
|
||||
@Override
|
||||
void addImports(Set<String> allImports) {
|
||||
super.addImports(allImports);
|
||||
allImports.add(assocPackage + "." + attributeSimpleName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package io.ebean.querybean.generator;
|
||||
|
||||
import java.util.AbstractMap.SimpleEntry;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Helper for splitting package and class name.
|
||||
*/
|
||||
@@ -31,4 +37,21 @@ class Split {
|
||||
return className.substring(startPos + 1);
|
||||
}
|
||||
|
||||
static Entry<String, Set<String>> genericsSplit(String signature) {
|
||||
StringBuilder simpleSignature = new StringBuilder();
|
||||
final StringTokenizer tokenizer = new StringTokenizer(signature, ",<> ", true);
|
||||
|
||||
Set<String> assocImports = new HashSet<>();
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
final String token = tokenizer.nextToken();
|
||||
if (token.length() == 1 && ",<> ".indexOf(token.charAt(0)) >= 0) {
|
||||
simpleSignature.append(token);
|
||||
} else {
|
||||
simpleSignature.append(Split.shortName(token));
|
||||
assocImports.add(token);
|
||||
}
|
||||
}
|
||||
return new SimpleEntry<>(simpleSignature.toString(), assocImports);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package io.ebean.querybean.generator;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
public class SplitTest {
|
||||
|
||||
@Test
|
||||
@@ -32,4 +35,9 @@ public class SplitTest {
|
||||
assertEquals(split[1], "Customer");
|
||||
}
|
||||
|
||||
}
|
||||
@Test
|
||||
public void split_generics() throws Exception {
|
||||
assertEquals("Foo<Bar, XFoo<XBar>>", Split.genericsSplit("com.Foo<com.Bar, org.XFoo<org.XBar>>").getKey());
|
||||
assertEquals(new HashSet<>(asList("com.Foo", "com.Bar", "org.XFoo", "org.XBar")), Split.genericsSplit("com.Foo<com.Bar, org.XFoo<org.XBar>>").getValue());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user