From e0fde5138f8da45de810304403bd14411229dc92 Mon Sep 17 00:00:00 2001 From: Nicolas Adment <39568358+nadment@users.noreply.github.com> Date: Sun, 1 Dec 2024 23:55:03 +0100 Subject: [PATCH] Move ValueMetaJson to Core library #4645 --- .../org/apache/hop/core/row/IValueMeta.java | 14 + .../core/row/value/ValueMetaAvroRecord.java | 2 +- .../hop/core/row/value/ValueMetaBase.java | 216 ++++++++- .../core/row/value/ValueMetaBigNumber.java | 2 +- .../hop/core/row/value/ValueMetaBinary.java | 2 +- .../hop/core/row/value/ValueMetaBoolean.java | 2 +- .../hop/core/row/value/ValueMetaDate.java | 2 +- .../hop/core/row/value/ValueMetaFactory.java | 4 + .../hop/core/row/value/ValueMetaInteger.java | 2 +- .../hop/core/row/value/ValueMetaJson.java | 110 +++++ .../hop/core/row/value/ValueMetaNone.java | 2 +- .../hop/core/row/value/ValueMetaNumber.java | 2 +- .../core/row/value/ValueMetaSerializable.java | 2 +- .../hop/core/row/value/ValueMetaString.java | 2 +- .../src/main/resources/images}/json.svg | 0 .../hop/neo4j/core/value/ValueMetaGraph.java | 3 +- plugins/valuetypes/json/pom.xml | 32 -- .../valuetypes/json/src/assembly/assembly.xml | 51 --- .../hop/core/row/value/ValueMetaJson.java | 413 ------------------ .../json/src/main/resources/version.xml | 20 - plugins/valuetypes/pom.xml | 4 +- 21 files changed, 354 insertions(+), 533 deletions(-) create mode 100644 core/src/main/java/org/apache/hop/core/row/value/ValueMetaJson.java rename {plugins/valuetypes/json/src/main/resources => core/src/main/resources/images}/json.svg (100%) delete mode 100644 plugins/valuetypes/json/pom.xml delete mode 100644 plugins/valuetypes/json/src/assembly/assembly.xml delete mode 100644 plugins/valuetypes/json/src/main/java/org/apache/hop/core/row/value/ValueMetaJson.java delete mode 100644 plugins/valuetypes/json/src/main/resources/version.xml 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 @@ * java.lang.byte[ * An array of bytes that contain any type of binary data. * + * + * Json + * TYPE_JSON + * com.fasterxml.jackson.databind.JsonNode + * A native Json object. + * * * *

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 @@ - - - - 4.0.0 - - - org.apache.hop - hop-plugins-valuetypes - 2.12.0-SNAPSHOT - - - hop-valuetypes-json - jar - Hop Plugins Value Types JSON - - diff --git a/plugins/valuetypes/json/src/assembly/assembly.xml b/plugins/valuetypes/json/src/assembly/assembly.xml deleted file mode 100644 index 8535b1665e6..00000000000 --- a/plugins/valuetypes/json/src/assembly/assembly.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - hop-valuetypes-json - - zip - - . - - - ${project.basedir}/src/main/resources/version.xml - plugins/valuetypes/json - true - - - - - - ${project.basedir}/src/main/samples - config/projects/samples/ - - - - - - - org.apache.hop:hop-valuetypes-json:jar - - plugins/valuetypes/json - - - \ No newline at end of file diff --git a/plugins/valuetypes/json/src/main/java/org/apache/hop/core/row/value/ValueMetaJson.java b/plugins/valuetypes/json/src/main/java/org/apache/hop/core/row/value/ValueMetaJson.java deleted file mode 100644 index 8f1f921a733..00000000000 --- a/plugins/valuetypes/json/src/main/java/org/apache/hop/core/row/value/ValueMetaJson.java +++ /dev/null @@ -1,413 +0,0 @@ -/* - * 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.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.math.BigDecimal; -import org.apache.hop.core.Const; -import org.apache.hop.core.exception.HopValueException; -import org.apache.hop.core.json.HopJson; -import org.apache.hop.core.row.IValueMeta; -import org.apache.hop.core.util.Utils; - -@ValueMetaPlugin(id = "11", name = "JSON", description = "JSON object", image = "json.svg") -public class ValueMetaJson extends ValueMetaBase implements IValueMeta { - - /** Value type indicating that the value contains a native JSON object */ - public static final int TYPE_JSON = 11; - - public static final String CONST_SPECIFIED = " specified."; - public static final String CONST_UNKNOWN_STORAGE_TYPE = " : Unknown storage type "; - - /** 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 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); - } - } - - 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); - } - } - - public ValueMetaJson() { - this(null); - } - - public ValueMetaJson(String name) { - super(name, TYPE_JSON); - prettyPrinting = true; - } - - 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() + CONST_UNKNOWN_STORAGE_TYPE + storageType + CONST_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() + CONST_UNKNOWN_STORAGE_TYPE + storageType + CONST_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() + CONST_UNKNOWN_STORAGE_TYPE + storageType + CONST_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() + CONST_UNKNOWN_STORAGE_TYPE + storageType + CONST_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() + CONST_UNKNOWN_STORAGE_TYPE + storageType + CONST_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() + CONST_UNKNOWN_STORAGE_TYPE + storageType + CONST_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 + CONST_SPECIFIED); - } - } - - @Override - public String getString(Object object) throws HopValueException { - return convertJsonToString(getJson(object)); - } - - @Override - public byte[] getBinaryString(Object object) throws HopValueException { - if (isStorageBinaryString() && identicalFormat) { - return (byte[]) object; // shortcut it directly for better performance. - } - if (object == null) { - return null; - } - 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() + CONST_UNKNOWN_STORAGE_TYPE + storageType + CONST_SPECIFIED); - } - } - - @Override - public Object convertDataFromString( - String pol, IValueMeta convertMeta, String nullIf, String ifNull, int trimType) - throws HopValueException { - // null handling and conversion of value to null - // - String nullValue = nullIf; - if (nullValue == null) { - switch (convertMeta.getType()) { - case IValueMeta.TYPE_BOOLEAN: - nullValue = Const.NULL_BOOLEAN; - break; - case IValueMeta.TYPE_STRING: - nullValue = Const.NULL_STRING; - break; - case IValueMeta.TYPE_BIGNUMBER: - nullValue = Const.NULL_BIGNUMBER; - break; - case IValueMeta.TYPE_NUMBER: - nullValue = Const.NULL_NUMBER; - break; - case IValueMeta.TYPE_INTEGER: - nullValue = Const.NULL_INTEGER; - break; - case IValueMeta.TYPE_DATE: - nullValue = Const.NULL_DATE; - break; - case IValueMeta.TYPE_BINARY: - nullValue = Const.NULL_BINARY; - break; - default: - nullValue = Const.NULL_NONE; - break; - } - } - - // See if we need to convert a null value into a String - // For example, we might want to convert null into "Empty". - // - if (!Utils.isEmpty(ifNull)) { - // Note that you can't pull the pad method up here as a nullComp variable - // because you could get an NPE since you haven't checked isEmpty(pol) - // yet! - if (Utils.isEmpty(pol) - || pol.equalsIgnoreCase(Const.rightPad(new StringBuilder(nullValue), pol.length()))) { - pol = ifNull; - } - } - - // See if the polled value is empty - // In that case, we have a null value on our hands... - // - if (Utils.isEmpty(pol)) { - return null; - } else { - // if the null_value is specified, we try to match with that. - // - if (!Utils.isEmpty(nullValue)) { - if (nullValue.length() <= pol.length()) { - // If the polled value is equal to the spaces right-padded null_value, - // we have a match - // - if (pol.equalsIgnoreCase(Const.rightPad(new StringBuilder(nullValue), pol.length()))) { - return null; - } - } - } else { - // Verify if there are only spaces in the polled value... - // We consider that empty as well... - // - if (Const.onlySpaces(pol)) { - return null; - } - } - } - - StringBuilder strpol; - // Trimming - switch (trimType) { - case IValueMeta.TRIM_TYPE_LEFT: - strpol = new StringBuilder(pol); - while (strpol.length() > 0 && strpol.charAt(0) == ' ') { - strpol.deleteCharAt(0); - } - pol = strpol.toString(); - - break; - case IValueMeta.TRIM_TYPE_RIGHT: - strpol = new StringBuilder(pol); - while (strpol.length() > 0 && strpol.charAt(strpol.length() - 1) == ' ') { - strpol.deleteCharAt(strpol.length() - 1); - } - pol = strpol.toString(); - - break; - case IValueMeta.TRIM_TYPE_BOTH: - strpol = new StringBuilder(pol); - while (strpol.length() > 0 && strpol.charAt(0) == ' ') { - strpol.deleteCharAt(0); - } - while (strpol.length() > 0 && strpol.charAt(strpol.length() - 1) == ' ') { - strpol.deleteCharAt(strpol.length() - 1); - } - pol = strpol.toString(); - break; - default: - break; - } - - // On with the regular program... - // Simply call the ValueMeta routines to do the conversion - // We need to do some effort here: copy all - // - return convertData(convertMeta, pol); - } - - /** - * Convert the specified data to the data type specified in this object. - * - * @param meta2 the metadata of the object to be converted - * @param data2 the data of the object to be converted - * @return the object in the data type of this value metadata object - * @throws HopValueException in case there is a data conversion error - */ - @Override - public Object convertData(IValueMeta meta2, Object data2) throws HopValueException { - switch (meta2.getType()) { - case TYPE_STRING: - return convertStringToJson(meta2.getString(data2)); - default: - throw new HopValueException( - meta2.toStringMeta() + " : can't be converted to an Internet Address"); - } - } - - @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/plugins/valuetypes/json/src/main/resources/version.xml b/plugins/valuetypes/json/src/main/resources/version.xml deleted file mode 100644 index 6be576acae9..00000000000 --- a/plugins/valuetypes/json/src/main/resources/version.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - -${project.version} \ No newline at end of file diff --git a/plugins/valuetypes/pom.xml b/plugins/valuetypes/pom.xml index cf383f41958..1864f3b5c5d 100644 --- a/plugins/valuetypes/pom.xml +++ b/plugins/valuetypes/pom.xml @@ -29,8 +29,6 @@ pom Hop Plugins Value Types - - json - +