Skip to content

Commit

Permalink
#651 - ENH: Add type support for java.nio.file.Path ... such that it …
Browse files Browse the repository at this point in the history
…stores the underlying URI as VARCHAR/string
  • Loading branch information
rbygrave committed Apr 20, 2016
1 parent 75e3b92 commit 221f5ad
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 11 deletions.
7 changes: 7 additions & 0 deletions src/main/java/com/avaje/ebean/config/ClassLoadConfig.java
Expand Up @@ -33,6 +33,13 @@ public boolean isJavaTimePresent() {
return isPresent("java.time.LocalDate");
}

/**
* Return true if Java7 is present.
*/
public boolean isJava7Present() {
return isPresent("java.nio.file.Path");
}

/**
* Return true if the Joda types are available and should be supported.
*/
Expand Down
Expand Up @@ -125,6 +125,8 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {

private final boolean objectMapperPresent;

private final boolean java7Present;

// OPTIONAL ScalarTypes registered if Jackson/JsonNode is in the classpath

/**
Expand Down Expand Up @@ -153,6 +155,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
*/
public DefaultTypeManager(ServerConfig config, BootupClasses bootupClasses) {

this.java7Present = config.getClassLoadConfig().isJava7Present();
this.jsonDateTime = config.getJsonDateTime();
this.checkImmutable = new CheckImmutable(this);
this.reflectScalarBuilder = new ReflectionBasedTypeBuilder(this);
Expand Down Expand Up @@ -282,19 +285,33 @@ public ScalarType<?> getScalarType(int jdbcType) {
/**
* This can return null if no matching ScalarType is found.
*/
@SuppressWarnings("unchecked")
public <T> ScalarType<T> getScalarType(Class<T> type) {
ScalarType<T> found = (ScalarType<T>) typeMap.get(type);
public ScalarType<?> getScalarType(Class<?> type) {
ScalarType<?> found = typeMap.get(type);
if (found == null) {
if (type.getName().equals("org.joda.time.LocalTime")) {
throw new IllegalStateException(
"ScalarType of Joda LocalTime not defined. You need to set ServerConfig.jodaLocalTimeMode to"
+ " either 'normal' or 'utc'. UTC is the old mode using UTC timezone but local time zone is now preferred as 'normal' mode.");
}
found = checkInterfaceTypes(type);
}
return found;
}

private ScalarType<?> checkInterfaceTypes(Class<?> type) {
if (java7Present) {
return checkJava7InterfaceTypes(type);
}
return null;
}

private ScalarType<?> checkJava7InterfaceTypes(Class<?> type) {
if (java.nio.file.Path.class.isAssignableFrom(type)) {
return typeMap.get(java.nio.file.Path.class);
}
return null;
}

public ScalarDataReader<?> getScalarDataReader(Class<?> propertyType, int sqlType) {

if (sqlType == 0) {
Expand Down Expand Up @@ -362,11 +379,11 @@ public ScalarType<?> getJsonScalarType(Class<?> type, int dbType) {
* </p>
*/
@SuppressWarnings("unchecked")
public <T> ScalarType<T> getScalarType(Class<T> type, int jdbcType) {
public ScalarType<?> getScalarType(Class<?> type, int jdbcType) {

// File is a special Lob so check for that first
if (File.class.equals(type)) {
return (ScalarType<T>) fileType;
return fileType;
}

// check for Clob, LongVarchar etc ...
Expand All @@ -375,23 +392,23 @@ public <T> ScalarType<T> getScalarType(Class<T> type, int jdbcType) {
ScalarType<?> scalarType = getLobTypes(jdbcType);
if (scalarType != null) {
// it is a specific Lob type...
return (ScalarType<T>) scalarType;
return scalarType;
}

scalarType = typeMap.get(type);
if (scalarType != null) {
if (jdbcType == 0 || scalarType.getJdbcType() == jdbcType) {
// matching type
return (ScalarType<T>) scalarType;
return scalarType;
}
}
// a util Date with jdbcType not matching server wide settings
if (type.equals(java.util.Date.class)) {
return (ScalarType<T>) extraTypeFactory.createUtilDate(jsonDateTime, jdbcType);
return extraTypeFactory.createUtilDate(jsonDateTime, jdbcType);
}
// a Calendar with jdbcType not matching server wide settings
if (type.equals(java.util.Calendar.class)) {
return (ScalarType<T>) extraTypeFactory.createCalendar(jsonDateTime, jdbcType);
return extraTypeFactory.createCalendar(jsonDateTime, jdbcType);
}

throw new IllegalArgumentException("Unmatched ScalarType for " + type + " jdbcType:" + jdbcType);
Expand Down Expand Up @@ -772,6 +789,11 @@ protected void initialiseJacksonTypes(ServerConfig config) {
}

protected void initialiseJavaTimeTypes(JsonConfig.DateTime mode, ServerConfig config) {

if (java7Present) {
typeMap.put(java.nio.file.Path.class, new ScalarTypePath());
}

if (config.getClassLoadConfig().isJavaTimePresent()) {
logger.debug("Registering java.time data types");
typeMap.put(java.time.LocalDate.class, new ScalarTypeLocalDate());
Expand Down
@@ -0,0 +1,40 @@
package com.avaje.ebeaninternal.server.type;

import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
* ScalarType for java.nio.file.Path which converts to and from a VARCHAR database column.
*/
public class ScalarTypePath extends ScalarTypeBaseVarchar<Path> {

public ScalarTypePath() {
super(Path.class);
}

@Override
public Path convertFromDbString(String dbValue) {
try {
return Paths.get(new URI(dbValue));
} catch (URISyntaxException e) {
throw new RuntimeException("Error with Path URI [" + dbValue + "] " + e);
}
}

@Override
public String convertToDbString(Path beanValue) {
return beanValue.toUri().toString();
}

@Override
public String formatValue(Path path) {
return convertToDbString(path);
}

@Override
public Path parse(String value) {
return convertFromDbString(value);
}
}
Expand Up @@ -42,14 +42,14 @@ public interface TypeManager {
/**
* Return the ScalarType for a given logical type.
*/
<T> ScalarType<T> getScalarType(Class<T> type);
ScalarType<?> getScalarType(Class<?> type);

/**
* For java.util.Date and java.util.Calendar additionally pass the jdbc type
* that you would like the ScalarType to map to. This is because these types
* can map to different java.sql.Types depending on the property.
*/
<T> ScalarType<T> getScalarType(Class<T> type, int jdbcType);
ScalarType<?> getScalarType(Class<?> type, int jdbcType);

/**
* Create a ScalarType for an Enum using a mapping (rather than JPA Ordinal
Expand Down
@@ -0,0 +1,36 @@
package com.avaje.ebeaninternal.server.type;

import org.junit.Test;

import java.nio.file.Path;
import java.nio.file.Paths;

import static org.junit.Assert.assertEquals;

public class ScalarTypePathTest {

private ScalarTypePath type = new ScalarTypePath();

@Test
public void convertFromDbString() throws Exception {

Path path = Paths.get(".");

String asString = type.convertToDbString(path);
Path converted = type.convertFromDbString(asString);

assertEquals(path, converted);
}

@Test
public void formatAndParse() throws Exception {

Path path = Paths.get(".");

String asString = type.formatValue(path);
Path converted = type.parse(asString);

assertEquals(path, converted);
}

}
11 changes: 11 additions & 0 deletions src/test/java/com/avaje/tests/model/types/SomeNewTypesBean.java
Expand Up @@ -4,6 +4,7 @@
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Version;
import java.nio.file.Path;
import java.time.*;

@Entity
Expand Down Expand Up @@ -41,6 +42,8 @@ public class SomeNewTypesBean {

ZoneOffset zoneOffset;

Path path;

public Long getId() {
return id;
}
Expand Down Expand Up @@ -144,4 +147,12 @@ public ZoneOffset getZoneOffset() {
public void setZoneOffset(ZoneOffset zoneOffset) {
this.zoneOffset = zoneOffset;
}

public Path getPath() {
return path;
}

public void setPath(Path path) {
this.path = path;
}
}
8 changes: 8 additions & 0 deletions src/test/java/com/avaje/tests/types/TestNewTypes.java
Expand Up @@ -6,6 +6,7 @@
import org.junit.Test;

import java.io.IOException;
import java.nio.file.Paths;
import java.time.*;
import java.util.List;

Expand All @@ -30,6 +31,7 @@ public void testInsertUpdate() throws IOException {
bean.setZoneId(ZoneId.systemDefault());
bean.setZoneOffset(ZonedDateTime.now().getOffset());
bean.setYearMonth(YearMonth.of(2014, 9));
bean.setPath(Paths.get("/tmp"));


Ebean.save(bean);
Expand Down Expand Up @@ -69,6 +71,9 @@ public void testInsertUpdate() throws IOException {
list = Ebean.find(SomeNewTypesBean.class).where().le("month", Month.SEPTEMBER).findList();
assertTrue(!list.isEmpty());

list = Ebean.find(SomeNewTypesBean.class).where().eq("path", Paths.get("/tmp")).findList();
assertTrue(!list.isEmpty());

SomeNewTypesBean fetched = Ebean.find(SomeNewTypesBean.class, bean.getId());

assertEquals(bean.getZoneId(), fetched.getZoneId());
Expand All @@ -80,6 +85,7 @@ public void testInsertUpdate() throws IOException {
assertEquals(bean.getLocalDateTime(), fetched.getLocalDateTime());
assertEquals(bean.getOffsetDateTime(), fetched.getOffsetDateTime());
assertEquals(bean.getInstant(), fetched.getInstant());
assertEquals(bean.getPath(), fetched.getPath());

String asJson = Ebean.json().toJson(fetched);

Expand All @@ -94,6 +100,7 @@ public void testInsertUpdate() throws IOException {
assertEquals(bean.getLocalDateTime(), toBean.getLocalDateTime());
assertEquals(bean.getOffsetDateTime(), toBean.getOffsetDateTime());
assertEquals(bean.getInstant(), toBean.getInstant());
assertEquals(bean.getPath(), toBean.getPath());

}

Expand All @@ -115,6 +122,7 @@ public void testInsertNull() {
assertNull(fetched.getLocalDateTime());
assertNull(fetched.getOffsetDateTime());
assertNull(fetched.getInstant());
assertNull(fetched.getPath());

}
}

0 comments on commit 221f5ad

Please sign in to comment.