diff --git a/core/src/main/java/org/apache/hop/core/row/IValueMeta.java b/core/src/main/java/org/apache/hop/core/row/IValueMeta.java index 34403eb1ad6..2d4121d66ae 100644 --- a/core/src/main/java/org/apache/hop/core/row/IValueMeta.java +++ b/core/src/main/java/org/apache/hop/core/row/IValueMeta.java @@ -18,6 +18,7 @@ package org.apache.hop.core.row; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -111,6 +112,12 @@ *
Storage Types
@@ -185,6 +192,9 @@ public interface IValueMeta extends Cloneable {
/** Value type indicating that the value contains an Internet address */
int TYPE_INET = 10;
+ /** Value type indicating that the value contains a native JSON object */
+ int TYPE_JSON = 11;
+
/** Value type indicating that the value contains an Avro Record */
int TYPE_AVRO = 20;
@@ -202,6 +212,7 @@ public interface IValueMeta extends Cloneable {
"Binary",
"Timestamp",
"Internet Address",
+ "Json"
};
/** The storage type is the same as the indicated value type */
@@ -893,6 +904,9 @@ static String getTypeDescription(int type) {
/** Convert the supplied data to a Boolean */
Boolean getBoolean(Object object) throws HopValueException;
+ /** Convert the supplied data to a Json */
+ JsonNode getJson(Object object) throws HopValueException;
+
/** Convert the supplied data to binary data */
byte[] getBinary(Object object) throws HopValueException;
diff --git a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaAvroRecord.java b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaAvroRecord.java
index f6ea24d8bd9..6fedf0a2140 100644
--- a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaAvroRecord.java
+++ b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaAvroRecord.java
@@ -49,7 +49,7 @@
name = "Avro Record",
description = "This type wraps around an Avro Record",
image = "images/avro.svg")
-public class ValueMetaAvroRecord extends ValueMetaBase implements IValueMeta {
+public class ValueMetaAvroRecord extends ValueMetaBase {
private Schema schema;
private static final String CONST_SCHEMA = "schema";
diff --git a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaBase.java b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaBase.java
index 0c09a317d04..0120949ede8 100644
--- a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaBase.java
+++ b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaBase.java
@@ -18,6 +18,14 @@
package org.apache.hop.core.row.value;
import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.core.json.JsonReadFeature;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.json.JsonMapper;
+import com.fasterxml.jackson.databind.node.BooleanNode;
+import com.fasterxml.jackson.databind.node.DecimalNode;
+import com.fasterxml.jackson.databind.node.DoubleNode;
+import com.fasterxml.jackson.databind.node.LongNode;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
@@ -58,6 +66,7 @@
import org.apache.hop.core.exception.HopException;
import org.apache.hop.core.exception.HopFileException;
import org.apache.hop.core.exception.HopValueException;
+import org.apache.hop.core.json.HopJson;
import org.apache.hop.core.logging.HopLogStore;
import org.apache.hop.core.logging.ILogChannel;
import org.apache.hop.core.row.IValueMeta;
@@ -1201,6 +1210,25 @@ protected synchronized Double convertStringToNumber(String string) throws HopVal
}
}
+ public String convertJsonToString(JsonNode jsonNode) throws HopValueException {
+ try {
+ ObjectMapper objectMapper = HopJson.newMapper();
+ return objectMapper.writeValueAsString(jsonNode);
+ } catch (Exception e) {
+ throw new HopValueException("Error converting JSON value to String", e);
+ }
+ }
+
+ public JsonNode convertStringToJson(String jsonString) throws HopValueException {
+ try {
+ ObjectMapper objectMapper =
+ JsonMapper.builder().enable(JsonReadFeature.ALLOW_UNQUOTED_FIELD_NAMES).build();
+ return objectMapper.readTree(jsonString);
+ } catch (Exception e) {
+ throw new HopValueException("Error converting string to JSON value: '" + jsonString + "'", e);
+ }
+ }
+
@Override
public synchronized SimpleDateFormat getDateFormat() {
return getDateFormat(getType());
@@ -2197,6 +2225,127 @@ public String getString(Object object) throws HopValueException {
}
}
+ @Override
+ public JsonNode getJson(Object object) throws HopValueException {
+ if (object == null) {
+ return null;
+ }
+
+ switch (type) {
+ case TYPE_JSON:
+ switch (storageType) {
+ case STORAGE_TYPE_NORMAL:
+ return (JsonNode) object;
+ case STORAGE_TYPE_BINARY_STRING:
+ return convertStringToJson(convertBinaryStringToString((byte[]) object));
+ case STORAGE_TYPE_INDEXED:
+ return (JsonNode) index[((Integer) object)];
+ default:
+ throw new HopValueException(
+ toString() + MSG_UNKNOWN_STORAGE_TYPE + storageType + MSG_SPECIFIED);
+ }
+ case TYPE_STRING:
+ switch (storageType) {
+ case STORAGE_TYPE_NORMAL:
+ return convertStringToJson((String) object);
+ case STORAGE_TYPE_BINARY_STRING:
+ return convertStringToJson((String) convertBinaryStringToNativeType((byte[]) object));
+ case STORAGE_TYPE_INDEXED:
+ return convertStringToJson((String) index[(Integer) object]);
+ default:
+ throw new HopValueException(
+ toString() + MSG_UNKNOWN_STORAGE_TYPE + storageType + MSG_SPECIFIED);
+ }
+ case TYPE_NUMBER:
+ Double number;
+ switch (storageType) {
+ case STORAGE_TYPE_NORMAL:
+ number = (Double) object;
+ break;
+ case STORAGE_TYPE_BINARY_STRING:
+ number = convertStringToNumber(convertBinaryStringToString((byte[]) object));
+ break;
+ case STORAGE_TYPE_INDEXED:
+ number = (Double) index[(Integer) object];
+ break;
+ default:
+ throw new HopValueException(
+ toString() + MSG_UNKNOWN_STORAGE_TYPE + storageType + MSG_SPECIFIED);
+ }
+ return new DoubleNode(number);
+
+ case TYPE_INTEGER:
+ Long integer;
+ switch (storageType) {
+ case STORAGE_TYPE_NORMAL:
+ integer = (Long) object;
+ break;
+ case STORAGE_TYPE_BINARY_STRING:
+ integer = (Long) convertBinaryStringToNativeType((byte[]) object);
+ break;
+ case STORAGE_TYPE_INDEXED:
+ integer = (Long) index[(Integer) object];
+ break;
+ default:
+ throw new HopValueException(
+ toString() + MSG_UNKNOWN_STORAGE_TYPE + storageType + MSG_SPECIFIED);
+ }
+ return new LongNode(integer);
+
+ case TYPE_BIGNUMBER:
+ BigDecimal bigDecimal;
+ switch (storageType) {
+ case STORAGE_TYPE_NORMAL:
+ bigDecimal = (BigDecimal) object;
+ break;
+ case STORAGE_TYPE_BINARY_STRING:
+ bigDecimal = (BigDecimal) convertBinaryStringToNativeType((byte[]) object);
+ break;
+ case STORAGE_TYPE_INDEXED:
+ bigDecimal = (BigDecimal) index[(Integer) object];
+ break;
+ default:
+ throw new HopValueException(
+ toString() + MSG_UNKNOWN_STORAGE_TYPE + storageType + MSG_SPECIFIED);
+ }
+ return new DecimalNode(bigDecimal);
+
+ case TYPE_BOOLEAN:
+ boolean bool;
+ switch (storageType) {
+ case STORAGE_TYPE_NORMAL:
+ bool = (Boolean) object;
+ break;
+ case STORAGE_TYPE_BINARY_STRING:
+ bool = (Boolean) convertBinaryStringToNativeType((byte[]) object);
+ break;
+ case STORAGE_TYPE_INDEXED:
+ bool = (Boolean) index[(Integer) object];
+ break;
+ default:
+ throw new HopValueException(
+ toString() + MSG_UNKNOWN_STORAGE_TYPE + storageType + MSG_SPECIFIED);
+ }
+ return BooleanNode.valueOf(bool);
+
+ case TYPE_DATE:
+ throw new HopValueException(
+ toString() + " : I don't know how to convert a date to a JSON object.");
+ case TYPE_TIMESTAMP:
+ throw new HopValueException(
+ toString() + " : I don't know how to convert a timestamp to a JSON object.");
+ case TYPE_BINARY:
+ throw new HopValueException(
+ toString() + " : I don't know how to convert a binary value to JSON object.");
+ case TYPE_SERIALIZABLE:
+ throw new HopValueException(
+ toString() + " : I don't know how to convert a serializable value to JSON object.");
+
+ default:
+ throw new HopValueException(toString() + " : Unknown type " + type + MSG_SPECIFIED);
+ }
+ }
+
protected String trim(String string) {
switch (getTrimType()) {
case TRIM_TYPE_NONE:
@@ -2928,6 +3077,21 @@ public byte[] getBinaryString(Object object) throws HopValueException {
+ MSG_SPECIFIED);
}
+ case TYPE_JSON:
+ switch (storageType) {
+ case STORAGE_TYPE_NORMAL:
+ return convertStringToBinaryString(getString(object));
+ case STORAGE_TYPE_BINARY_STRING:
+ return convertStringToBinaryString(
+ getString(convertStringToJson(convertBinaryStringToString((byte[]) object))));
+ case STORAGE_TYPE_INDEXED:
+ return convertStringToBinaryString(
+ convertJsonToString((JsonNode) index[((Integer) object)]));
+ default:
+ throw new HopValueException(
+ toString() + MSG_UNKNOWN_STORAGE_TYPE + storageType + MSG_SPECIFIED);
+ }
+
case TYPE_SERIALIZABLE:
switch (storageType) {
case STORAGE_TYPE_NORMAL:
@@ -3191,6 +3355,9 @@ public void writeData(DataOutputStream outputStream, Object object) throws HopFi
case TYPE_BINARY:
writeBinary(outputStream, (byte[]) object);
break;
+ case TYPE_JSON:
+ writeJson(outputStream, (JsonNode) object);
+ break;
case TYPE_INET:
writeBinary(outputStream, ((InetAddress) object).getAddress());
break;
@@ -3259,6 +3426,8 @@ public Object readData(DataInputStream inputStream)
return readBoolean(inputStream);
case TYPE_BINARY:
return readBinary(inputStream);
+ case TYPE_JSON:
+ return readJson(inputStream);
case TYPE_INET:
return InetAddress.getByAddress(readBinary(inputStream));
default:
@@ -3296,6 +3465,19 @@ protected void writeString(DataOutputStream outputStream, String string) throws
}
}
+ protected void writeJson(DataOutputStream outputStream, JsonNode jsonNode) throws IOException {
+ // Write the length and then the bytes
+ if (jsonNode == null) {
+ outputStream.writeInt(-1);
+ } else {
+ ObjectMapper objectMapper = new ObjectMapper();
+ String string = objectMapper.writeValueAsString(jsonNode);
+ byte[] chars = string.getBytes(Const.XML_ENCODING);
+ outputStream.writeInt(chars.length);
+ outputStream.write(chars);
+ }
+ }
+
protected void writeBinaryString(DataOutputStream outputStream, byte[] binaryString)
throws IOException {
// Write the length and then the bytes
@@ -3320,7 +3502,7 @@ protected String readString(DataInputStream inputStream) throws IOException {
return new String(chars, Const.XML_ENCODING);
}
- protected byte[] readBinaryString(DataInputStream inputStream) throws IOException {
+ protected JsonNode readJson(DataInputStream inputStream) throws IOException {
// Read the inputLength and then the bytes
int inputLength = inputStream.readInt();
if (inputLength < 0) {
@@ -3330,6 +3512,20 @@ protected byte[] readBinaryString(DataInputStream inputStream) throws IOExceptio
byte[] chars = new byte[inputLength];
inputStream.readFully(chars);
+ ObjectMapper objectMapper = new ObjectMapper();
+ return objectMapper.readTree(chars, 0, inputLength);
+ }
+
+ protected byte[] readBinaryString(DataInputStream inputStream) throws IOException {
+ // Read the length and then the bytes
+ int inputLength = inputStream.readInt();
+ if (inputLength < 0) {
+ return null;
+ }
+
+ byte[] chars = new byte[inputLength];
+ inputStream.readFully(chars);
+
return chars;
}
@@ -3440,6 +3636,9 @@ public void writeMeta(DataOutputStream outputStream) throws HopFileException {
case TYPE_BINARY:
writeBinary(outputStream, (byte[]) index[i]);
break;
+ case TYPE_JSON:
+ writeJson(outputStream, (JsonNode) index[i]);
+ break;
default:
throw new HopFileException(
this
@@ -3578,6 +3777,9 @@ public void readMetaData(DataInputStream inputStream) throws HopFileException {
case TYPE_BINARY:
index[i] = readBinary(inputStream);
break;
+ case TYPE_JSON:
+ index[i] = readJson(inputStream);
+ break;
default:
throw new HopFileException(
this
@@ -4291,6 +4493,8 @@ public Object convertData(IValueMeta meta2, Object data2) throws HopValueExcepti
return meta2.getBoolean(data2);
case TYPE_BINARY:
return meta2.getBinary(data2);
+ case TYPE_JSON:
+ return meta2.getJson(data2);
default:
throw new HopValueException(this + CONST_CANNOT_CONVERT + getType());
}
@@ -4322,6 +4526,8 @@ public Object convertDataCompatible(IValueMeta meta2, Object data2) throws HopVa
return meta2.getBoolean(data2);
case TYPE_BINARY:
return meta2.getBinary(data2);
+ case TYPE_JSON:
+ return meta2.getJson(data2);
default:
throw new HopValueException(this + CONST_CANNOT_CONVERT + getType());
}
@@ -4349,7 +4555,6 @@ public Object convertDataUsingConversionMetaData(Object data) throws HopValueExc
// storageMetaData to get the correct conversion mask
// That way we're always sure that a conversion works both ways.
//
-
switch (conversionMetadata.getType()) {
case TYPE_STRING:
return getString(data);
@@ -4367,6 +4572,8 @@ public Object convertDataUsingConversionMetaData(Object data) throws HopValueExc
return getBinary(data);
case TYPE_TIMESTAMP:
return getDate(data);
+ case TYPE_JSON:
+ return getJson(data);
default:
throw new HopValueException(this + CONST_CANNOT_CONVERT + conversionMetadata.getType());
}
@@ -4557,6 +4764,8 @@ public int hashCode(Object object) throws HopValueException {
case TYPE_INET:
hash ^= 256;
break;
+ case TYPE_JSON:
+ hash ^= 512;
case TYPE_NONE:
break;
default:
@@ -4591,6 +4800,9 @@ public int hashCode(Object object) throws HopValueException {
case TYPE_INET:
hash ^= object.hashCode();
break;
+ case TYPE_JSON:
+ hash ^= object.hashCode();
+ break;
case TYPE_NONE:
break;
default:
diff --git a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaBigNumber.java b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaBigNumber.java
index e71cd117f04..bc264aef905 100644
--- a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaBigNumber.java
+++ b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaBigNumber.java
@@ -26,7 +26,7 @@
name = "BigNumber",
description = "BigNumber",
image = "images/number.svg")
-public class ValueMetaBigNumber extends ValueMetaBase implements IValueMeta {
+public class ValueMetaBigNumber extends ValueMetaBase {
public ValueMetaBigNumber() {
this(null);
diff --git a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaBinary.java b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaBinary.java
index 93cec837a48..541cad46d6e 100644
--- a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaBinary.java
+++ b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaBinary.java
@@ -21,7 +21,7 @@
import org.apache.hop.core.row.IValueMeta;
@ValueMetaPlugin(id = "8", name = "Binary", description = "Binary", image = "images/binary.svg")
-public class ValueMetaBinary extends ValueMetaBase implements IValueMeta {
+public class ValueMetaBinary extends ValueMetaBase {
public ValueMetaBinary() {
this(null);
diff --git a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaBoolean.java b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaBoolean.java
index 6c377165eb2..d512cc3b4d8 100644
--- a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaBoolean.java
+++ b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaBoolean.java
@@ -21,7 +21,7 @@
import org.apache.hop.core.row.IValueMeta;
@ValueMetaPlugin(id = "4", name = "Boolean", description = "Boolean", image = "images/boolean.svg")
-public class ValueMetaBoolean extends ValueMetaBase implements IValueMeta {
+public class ValueMetaBoolean extends ValueMetaBase {
public ValueMetaBoolean() {
this(null);
diff --git a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaDate.java b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaDate.java
index 4b032674f9a..4e31c8ea1b1 100644
--- a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaDate.java
+++ b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaDate.java
@@ -22,7 +22,7 @@
import org.apache.hop.core.row.IValueMeta;
@ValueMetaPlugin(id = "3", name = "Date", description = "Date", image = "images/date.svg")
-public class ValueMetaDate extends ValueMetaBase implements IValueMeta {
+public class ValueMetaDate extends ValueMetaBase {
public ValueMetaDate() {
this(null);
diff --git a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaFactory.java b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaFactory.java
index 22a174a67b5..850a4924ee2 100644
--- a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaFactory.java
+++ b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaFactory.java
@@ -17,6 +17,7 @@
package org.apache.hop.core.row.value;
+import com.fasterxml.jackson.databind.JsonNode;
import java.io.DataInputStream;
import java.io.EOFException;
import java.math.BigDecimal;
@@ -211,7 +212,10 @@ public static IValueMeta guessValueMetaInterface(Object object) {
return new ValueMetaBoolean();
} else if (object instanceof byte[]) {
return new ValueMetaBinary();
+ } else if (object instanceof JsonNode) {
+ return new ValueMetaJson();
}
+
// ask someone else
return null;
}
diff --git a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaInteger.java b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaInteger.java
index 72cfa0dd911..8064852dc43 100644
--- a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaInteger.java
+++ b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaInteger.java
@@ -21,7 +21,7 @@
import org.apache.hop.core.row.IValueMeta;
@ValueMetaPlugin(id = "5", name = "Integer", description = "Integer", image = "images/number.svg")
-public class ValueMetaInteger extends ValueMetaBase implements IValueMeta {
+public class ValueMetaInteger extends ValueMetaBase {
public ValueMetaInteger() {
this(null);
diff --git a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaJson.java b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaJson.java
new file mode 100644
index 00000000000..2d71bff07fa
--- /dev/null
+++ b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaJson.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.hop.core.row.value;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.hop.core.exception.HopValueException;
+import org.apache.hop.core.json.HopJson;
+
+@ValueMetaPlugin(id = "11", name = "JSON", description = "JSON object", image = "images/json.svg")
+public class ValueMetaJson extends ValueMetaBase {
+
+ /** Do String serialization using pretty printing? */
+ private boolean prettyPrinting;
+
+ @Override
+ public int compare(Object data1, Object data2) throws HopValueException {
+ JsonNode json1 = (JsonNode) data1;
+ JsonNode json2 = (JsonNode) data2;
+
+ String string1 = convertJsonToString(json1);
+ String string2 = convertJsonToString(json2);
+
+ return string1.compareTo(string2);
+ }
+
+ public ValueMetaJson() {
+ this(null);
+ }
+
+ public ValueMetaJson(String name) {
+ super(name, TYPE_JSON);
+ prettyPrinting = true;
+ }
+
+ @Override
+ public String getString(Object object) throws HopValueException {
+ return convertJsonToString(getJson(object));
+ }
+
+ @Override
+ public String convertJsonToString(JsonNode jsonNode) throws HopValueException {
+ try {
+ ObjectMapper objectMapper = HopJson.newMapper();
+ if (prettyPrinting) {
+ return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonNode);
+ } else {
+ return objectMapper.writeValueAsString(jsonNode);
+ }
+ } catch (Exception e) {
+ throw new HopValueException("Error converting JSON value to String", e);
+ }
+ }
+
+ @Override
+ public Object cloneValueData(Object object) throws HopValueException {
+ JsonNode jsonNode = getJson(object);
+ if (jsonNode == null) {
+ return null;
+ }
+
+ try {
+ String jsonString = convertJsonToString(jsonNode);
+ return convertStringToJson(jsonString);
+ } catch (Exception e) {
+ throw new HopValueException("Unable to clone JSON value", e);
+ }
+ }
+
+ @Override
+ public Object getNativeDataType(Object object) throws HopValueException {
+ return getJson(object);
+ }
+
+ @Override
+ public Class> getNativeDataTypeClass() throws HopValueException {
+ return JsonNode.class;
+ }
+
+ /**
+ * Gets prettyPrinting
+ *
+ * @return value of prettyPrinting
+ */
+ public boolean isPrettyPrinting() {
+ return prettyPrinting;
+ }
+
+ /**
+ * @param prettyPrinting The prettyPrinting to set
+ */
+ public void setPrettyPrinting(boolean prettyPrinting) {
+ this.prettyPrinting = prettyPrinting;
+ }
+}
diff --git a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaNone.java b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaNone.java
index 5c891722820..fc96fd41357 100644
--- a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaNone.java
+++ b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaNone.java
@@ -21,7 +21,7 @@
import org.apache.hop.core.row.IValueMeta;
@ValueMetaPlugin(id = "0", name = "None", description = "None")
-public class ValueMetaNone extends ValueMetaBase implements IValueMeta {
+public class ValueMetaNone extends ValueMetaBase {
public ValueMetaNone() {
this(null);
diff --git a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaNumber.java b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaNumber.java
index efffde7e4d6..5f4010379ff 100644
--- a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaNumber.java
+++ b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaNumber.java
@@ -21,7 +21,7 @@
import org.apache.hop.core.row.IValueMeta;
@ValueMetaPlugin(id = "1", name = "Number", description = "Number", image = "images/number.svg")
-public class ValueMetaNumber extends ValueMetaBase implements IValueMeta {
+public class ValueMetaNumber extends ValueMetaBase {
public ValueMetaNumber() {
this(null);
diff --git a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaSerializable.java b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaSerializable.java
index 06190731f36..1e996a03ce7 100644
--- a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaSerializable.java
+++ b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaSerializable.java
@@ -24,7 +24,7 @@
name = "Serializable",
description = "Serializable",
image = "images/binary.svg")
-public class ValueMetaSerializable extends ValueMetaBase implements IValueMeta {
+public class ValueMetaSerializable extends ValueMetaBase {
public ValueMetaSerializable() {
this(null);
diff --git a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaString.java b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaString.java
index 8ca310c000e..57bb84132b6 100644
--- a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaString.java
+++ b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaString.java
@@ -22,7 +22,7 @@
import org.apache.hop.core.row.IValueMeta;
@ValueMetaPlugin(id = "2", name = "String", description = "String", image = "images/string.svg")
-public class ValueMetaString extends ValueMetaBase implements IValueMeta {
+public class ValueMetaString extends ValueMetaBase {
public ValueMetaString() {
this(null);
diff --git a/plugins/valuetypes/json/src/main/resources/json.svg b/core/src/main/resources/images/json.svg
similarity index 100%
rename from plugins/valuetypes/json/src/main/resources/json.svg
rename to core/src/main/resources/images/json.svg
diff --git a/plugins/tech/neo4j/src/main/java/org/apache/hop/neo4j/core/value/ValueMetaGraph.java b/plugins/tech/neo4j/src/main/java/org/apache/hop/neo4j/core/value/ValueMetaGraph.java
index eade7204b58..cd34fc47b63 100644
--- a/plugins/tech/neo4j/src/main/java/org/apache/hop/neo4j/core/value/ValueMetaGraph.java
+++ b/plugins/tech/neo4j/src/main/java/org/apache/hop/neo4j/core/value/ValueMetaGraph.java
@@ -20,7 +20,6 @@
import org.apache.hop.core.exception.HopException;
import org.apache.hop.core.exception.HopValueException;
-import org.apache.hop.core.row.IValueMeta;
import org.apache.hop.core.row.ValueDataUtil;
import org.apache.hop.core.row.value.ValueMetaBase;
import org.apache.hop.core.row.value.ValueMetaPlugin;
@@ -32,7 +31,7 @@
name = "Graph",
image = "graph.svg",
description = "Graph data type containing nodes, relationships and their properties")
-public class ValueMetaGraph extends ValueMetaBase implements IValueMeta {
+public class ValueMetaGraph extends ValueMetaBase {
/**
* 303 is the number of the room where the movie "The Matrix" starts and where Neo is short by
diff --git a/plugins/valuetypes/json/pom.xml b/plugins/valuetypes/json/pom.xml
deleted file mode 100644
index 1edcc955d2e..00000000000
--- a/plugins/valuetypes/json/pom.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-