Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ target/
.classpath
.project
.settings/

# IntelliJ #
.idea/
.iml
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
<modules>
<module>imagej/imagej-ops2</module>
<module>imagej/imagej-testutil</module>
<module>scijava/scijava-persist</module>
<module>scijava/scijava-ops</module>
<module>scijava/scijava-testutil</module>
<module>scijava/scijava-types</module>
Expand Down
6 changes: 6 additions & 0 deletions scijava/scijava-persist/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/.classpath
/.project
/.settings/
/.idea/
/target/
*.iml
10 changes: 10 additions & 0 deletions scijava/scijava-persist/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#Scijava mechanism for object serialization

This incubator contains a mechanism that uses Scijava extensibility mechanism in order to register adapters that can be dispatched in multiple repositories.

Internally the Gson library is used with `RunTimeAdapters`, which allow to serialize interfaces.

TODO:
* simple examples
* tests
* think about safety, or at least debugging ease (put a UUID)
116 changes: 116 additions & 0 deletions scijava/scijava-persist/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?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">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.scijava</groupId>
<artifactId>scijava-incubator</artifactId>
<version>0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>

<artifactId>scijava-persist</artifactId>

<name>SciJava Persist</name>
<description>Extensible serialization mechanism for persisting objects.</description>
<url>None</url>
<inceptionYear>2021</inceptionYear>
<organization>
<name>SciJava</name>
<url>https://scijava.org/</url>
</organization>
<licenses>
<license>
<name>Simplified BSD License</name>
<distribution>repo</distribution>
</license>
</licenses>


<developers>
<developer>
<id>nicokiaru</id>
<name>Nicolas Chiaruttini</name>
<url>https://www.epfl.ch/research/facilities/ptbiop/staff/</url>
<roles>
<role>founder</role>
<role>lead</role>
<role>developer</role>
<role>debugger</role>
<role>reviewer</role>
<role>support</role>
<role>maintainer</role>
</roles>
</developer>
</developers>
<contributors>
<contributor>
<name>Nicolas Chiaruttini</name>
<url>http://biop.epfl.ch/INFO_Facility.html</url>
<roles><role>founder</role></roles>
<properties><id>NicoKiaru</id></properties>
</contributor>
</contributors>

<mailingLists>
<mailingList>
<name>Image.sc Forum</name>
<archive>https://forum.image.sc/tag/scijava</archive>
</mailingList>
</mailingLists>

<scm>
<connection>scm:git:git://github.com/scijava/incubator</connection>
<developerConnection>scm:git:git@github.com:scijava/incubator</developerConnection>
<tag>HEAD</tag>
<url>https://github.com/scijava/incubator</url>
</scm>

<issueManagement>
<system>GitHub Issues</system>
<url>https://github.com/scijava/scijava-testutil/issues</url>
</issueManagement>
<ciManagement>
<system>Travis CI</system>
<url>https://travis-ci.org/scijava/incubator</url>
</ciManagement>


<properties>
<main-class>org.scijava.persist.Main</main-class>
<package-name>org.scijava.persist</package-name>

<license.licenseName>bsd_2</license.licenseName>
<license.copyrightOwners>SciJava developers.</license.copyrightOwners>
</properties>

<repositories>
<repository>
<id>scijava.public</id>
<url>https://maven.scijava.org/content/groups/public</url>
</repository>
</repositories>

<dependencies>
<dependency>
<groupId>org.scijava</groupId>
<artifactId>scijava-common</artifactId>
</dependency>

<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>

<!--- Test dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
7 changes: 7 additions & 0 deletions scijava/scijava-persist/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
open module org.scijava.persist {

exports org.scijava.persist;

requires transitive com.google.gson;
requires org.scijava;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package org.scijava.persist;

import org.scijava.Context;
import org.scijava.Priority;
import org.scijava.plugin.AbstractPTService;
import org.scijava.plugin.Parameter;
import org.scijava.plugin.Plugin;
import org.scijava.plugin.PluginInfo;
import org.scijava.service.Service;

import java.util.List;

/**
* Scijava service which provides the different Scijava Adapters available in the current context.
*
* {@link IObjectScijavaAdapter} plugins are automatically discovered and accessible in this service.
*
* In practice, serializer / deserializers are obtained via {@link ScijavaGsonHelper} helper class
*
* @author Nicolas Chiaruttini, EPFL, 2021
*
*/
@Plugin(type = Service.class)
public class DefaultScijavaAdapterService extends AbstractPTService<IObjectScijavaAdapter> implements IObjectScijavaAdapterService {

@Override
public Class<IObjectScijavaAdapter> getPluginType() {
return IObjectScijavaAdapter.class;
}

@Parameter
Context ctx;

@Override
public Context context() {
return ctx;
}

@Override
public Context getContext() {
return ctx;
}

double priority = Priority.NORMAL;

@Override
public double getPriority() {
return priority;
}

@Override
public void setPriority(double priority) {
this.priority = priority;
}

@Override
public <PT extends IObjectScijavaAdapter> List<PluginInfo<PT>> getAdapters(Class<PT> adapterClass) {
return pluginService().getPluginsOfType(adapterClass);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.scijava.persist;

import com.google.gson.JsonDeserializer;
import com.google.gson.JsonSerializer;

public interface IClassAdapter<T> extends IObjectScijavaAdapter, JsonSerializer<T>,
JsonDeserializer<T> {

Class<? extends T> getAdapterClass();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.scijava.persist;

import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonSerializer;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonParseException;
import com.google.gson.JsonIOException;

import java.lang.reflect.Type;

public interface IClassRuntimeAdapter<B, T extends B> extends IObjectScijavaAdapter, JsonSerializer<T>,
JsonDeserializer<T> {

Class<? extends B> getBaseClass();

Class<? extends T> getRunTimeClass();

default boolean useCustomAdapter() {
return false;
}

@Override
default T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
throw new JsonParseException("Default deserializer for class "+getBaseClass()+" ("+getRunTimeClass()+") should not be used, return false in method useCustomAdapter instead");
}

@Override
default JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) {
throw new JsonIOException("Default serializer for class "+getBaseClass()+" ("+getRunTimeClass()+") should not be used, should not be used, return false in method useCustomAdapter instead");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.scijava.persist;

import org.scijava.plugin.SciJavaPlugin;

/**
* Top level class for plugins which can serialize object using gson and the scijava context.
*
* The scijava context may provide custom adapters {@link IClassAdapter} and also
* runtime adapters, see {@link IClassRuntimeAdapter}) auto-discovered via scijava plugin
* extensibility mechanism.
*
* @author Nicolas Chiaruttini, EPFL, 2021
*
*/

public interface IObjectScijavaAdapter extends SciJavaPlugin {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.scijava.persist;

import org.scijava.plugin.PTService;
import org.scijava.plugin.PluginInfo;
import org.scijava.service.SciJavaService;

import java.util.List;

public interface IObjectScijavaAdapterService extends PTService<IObjectScijavaAdapter>, SciJavaService {
<PT extends IObjectScijavaAdapter> List<PluginInfo<PT>> getAdapters(Class<PT> adapterClass);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.scijava.persist;

import java.io.ObjectStreamException;
import java.math.BigDecimal;

/**
* This class holds a number value that is lazily converted to a specific number type
*
* @author Inderjeet Singh
*/
public final class LazilyParsedNumber extends Number {
private final String value;

/** @param value must not be null */
public LazilyParsedNumber(String value) {
this.value = value;
}

@Override
public int intValue() {
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
try {
return (int) Long.parseLong(value);
} catch (NumberFormatException nfe) {
return new BigDecimal(value).intValue();
}
}
}

@Override
public long longValue() {
try {
return Long.parseLong(value);
} catch (NumberFormatException e) {
return new BigDecimal(value).longValue();
}
}

@Override
public float floatValue() {
return Float.parseFloat(value);
}

@Override
public double doubleValue() {
return Double.parseDouble(value);
}

@Override
public String toString() {
return value;
}

/**
* If somebody is unlucky enough to have to serialize one of these, serialize
* it as a BigDecimal so that they won't need Gson on the other side to
* deserialize it.
*/
private Object writeReplace() throws ObjectStreamException {
return new BigDecimal(value);
}

@Override
public int hashCode() {
return value.hashCode();
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof LazilyParsedNumber) {
LazilyParsedNumber other = (LazilyParsedNumber) obj;
return value == other.value || value.equals(other.value);
}
return false;
}
}
Loading