Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avro 1605 - Remove Jackson classes from public API #135

Closed
wants to merge 7 commits into from
44 changes: 26 additions & 18 deletions lang/java/avro/src/main/java/org/apache/avro/JsonProperties.java
Expand Up @@ -20,9 +20,12 @@
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.io.IOException;

import org.apache.avro.util.internal.Accessor;
import org.apache.avro.util.internal.Accessor.JsonPropertiesAccessor;
import org.apache.avro.util.internal.JacksonUtils;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonGenerator;
Expand Down Expand Up @@ -108,6 +111,16 @@
* @see org.apache.avro.data.Json
*/
public abstract class JsonProperties {

static {
Accessor.setAccessor(new JsonPropertiesAccessor() {
@Override
protected void addProp(JsonProperties props, String name, JsonNode value) {
props.addProp(name, value);
}
});
}

public static class Null {
private Null() {}
}
Expand All @@ -134,10 +147,8 @@ public String getProp(String name) {
/**
* Returns the value of the named property in this schema.
* Returns <tt>null</tt> if there is no property with that name.
* @deprecated use {@link #getObjectProp(String)}
*/
@Deprecated
public synchronized JsonNode getJsonProp(String name) {
synchronized JsonNode getJsonProp(String name) {
return props.get(name);
}

Expand All @@ -162,18 +173,7 @@ public void addProp(String name, String value) {
addProp(name, TextNode.valueOf(value));
}

/**
* Adds a property with the given name <tt>name</tt> and
* value <tt>value</tt>. Neither <tt>name</tt> nor <tt>value</tt> can be
* <tt>null</tt>. It is illegal to add a property if another with
* the same name but different value already exists in this schema.
*
* @param name The name of the property to add
* @param value The value for the property to add
* @deprecated use {@link #addProp(String, Object)}
*/
@Deprecated
public synchronized void addProp(String name, JsonNode value) {
synchronized void addProp(String name, JsonNode value) {
if (reserved.contains(name))
throw new AvroRuntimeException("Can't set reserved property: " + name);

Expand All @@ -191,6 +191,16 @@ public synchronized void addProp(String name, Object value) {
addProp(name, JacksonUtils.toJsonNode(value));
}

/**
* Adds all the props from the specified json properties.
*
* @see #getObjectProps()
*/
public void addAllProps(JsonProperties properties) {
for (Entry<String, JsonNode> entry : properties.getJsonProps().entrySet())
addProp(entry.getKey(), entry.getValue());
}

/** Return the defined properties that have string values. */
@Deprecated public Map<String,String> getProps() {
Map<String,String> result = new LinkedHashMap<String,String>();
Expand All @@ -210,10 +220,8 @@ Map<String,JsonNode> jsonProps(Map<String,String> stringProps) {

/**
* Return the defined properties as an unmodifieable Map.
* @deprecated use {@link #getObjectProps()}
*/
@Deprecated
public Map<String,JsonNode> getJsonProps() {
Map<String,JsonNode> getJsonProps() {
return Collections.unmodifiableMap(props);
}

Expand Down
21 changes: 21 additions & 0 deletions lang/java/avro/src/main/java/org/apache/avro/Protocol.java
Expand Up @@ -230,6 +230,15 @@ private Protocol() {
super(PROTOCOL_RESERVED);
}

/**
* Constructs a similar Protocol instance with the same {@code name}, {@code doc}, and {@code namespace} as {code p}
* has. It also copies all the {@code props}.
*/
public Protocol(Protocol p) {
this(p.getName(), p.getDoc(), p.getNamespace());
props.putAll(p.props);
}

public Protocol(String name, String doc, String namespace) {
super(PROTOCOL_RESERVED);
this.name = name;
Expand Down Expand Up @@ -270,6 +279,12 @@ public void setTypes(Collection<Schema> newTypes) {
public Message createMessage(String name, String doc, Schema request) {
return createMessage(name, doc, new LinkedHashMap<String,String>(),request);
}

/** Create a one-way message using the {@code name}, {@code doc}, and {@code props} of {@code m}. */
public Message createMessage(Message m, Schema request) {
return createMessage(m.getName(), m.getDoc(), m.getJsonProps(), request);
}

/** Create a one-way message. */
public <T> Message createMessage(String name, String doc,
Map<String,T> propMap, Schema request) {
Expand All @@ -283,6 +298,12 @@ public Message createMessage(String name, String doc, Schema request,
return createMessage(name, doc, new LinkedHashMap<String,String>(),
request, response, errors);
}

/** Create a two-way message using the {@code name}, {@code doc}, and {@code props} of {@code m}. */
public Message createMessage(Message m, Schema request, Schema response, Schema errors) {
return createMessage(m.getName(), m.getDoc(), m.getJsonProps(), request, response, errors);
}

/** Create a two-way message. */
public <T> Message createMessage(String name, String doc,
Map<String,T> propMap, Schema request,
Expand Down
68 changes: 48 additions & 20 deletions lang/java/avro/src/main/java/org/apache/avro/Schema.java
Expand Up @@ -36,6 +36,8 @@
import java.util.Map;
import java.util.Set;

import org.apache.avro.util.internal.Accessor;
import org.apache.avro.util.internal.Accessor.FieldAccessor;
import org.apache.avro.util.internal.JacksonUtils;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonNode;
Expand Down Expand Up @@ -130,7 +132,7 @@ public static Schema create(Type type) {

int hashCode = NO_HASHCODE;

@Override public void addProp(String name, JsonNode value) {
@Override void addProp(String name, JsonNode value) {
super.addProp(name, value);
hashCode = NO_HASHCODE;
}
Expand Down Expand Up @@ -374,6 +376,25 @@ final boolean equalCachedHash(Schema other) {
/** A field within a record. */
public static class Field extends JsonProperties {

static {
Accessor.setAccessor(new FieldAccessor() {
@Override
protected JsonNode defaultValue(Field field) {
return field.defaultValue();
}

@Override
protected Field createField(String name, Schema schema, String doc, JsonNode defaultValue) {
return new Field(name, schema, doc, defaultValue);
}

@Override
protected Field createField(String name, Schema schema, String doc, JsonNode defaultValue, Order order) {
return new Field(name, schema, doc, defaultValue, order);
}
});
}

/** How values of this field should be ordered when sorting records. */
public enum Order {
ASCENDING, DESCENDING, IGNORE;
Expand All @@ -389,23 +410,31 @@ public enum Order {
private final Order order;
private Set<String> aliases;

/** @deprecated use {@link #Field(String, Schema, String, Object)} */
@Deprecated
public Field(String name, Schema schema, String doc,
Field(String name, Schema schema, String doc,
JsonNode defaultValue) {
this(name, schema, doc, defaultValue, Order.ASCENDING);
}
/** @deprecated use {@link #Field(String, Schema, String, Object, Order)} */
@Deprecated
public Field(String name, Schema schema, String doc,
JsonNode defaultValue, Order order) {
Field(String name, Schema schema, String doc,
JsonNode defaultValue, Order order) {
super(FIELD_RESERVED);
this.name = validateName(name);
this.schema = schema;
this.doc = doc;
this.defaultValue = validateDefault(name, schema, defaultValue);
this.order = order;
}

/**
* Constructs a new Field instance with the same {@code name}, {@code doc}, {@code defaultValue}, and {@code order}
* as {@code field} has with changing the schema to the specified one. It also copies all the {@code props} and
* {@code aliases}.
*/
public Field(Field field, Schema schema) {
this(field.name, schema, field.doc, field.defaultValue, field.order);
props.putAll(field.props);
if (field.aliases != null)
aliases = new LinkedHashSet<String>(field.aliases);
}
/**
* @param defaultValue the default value for this field specified using the mapping
* in {@link JsonProperties}
Expand All @@ -429,8 +458,7 @@ public Field(String name, Schema schema, String doc,
public Schema schema() { return schema; }
/** Field's documentation within the record, if set. May return null. */
public String doc() { return doc; }
/** @deprecated use {@link #defaultVal() } */
@Deprecated public JsonNode defaultValue() { return defaultValue; }
JsonNode defaultValue() { return defaultValue; }
/**
* @return the default value for this field specified using the mapping
* in {@link JsonProperties}
Expand Down Expand Up @@ -1045,8 +1073,7 @@ private Schema parse(JsonParser parser) throws IOException {
* The contents of <tt>file</tt> is expected to be in UTF-8 format.
* @param file The file to read the schema from.
* @return The freshly built Schema.
* @throws IOException if there was trouble reading the contents
* @throws JsonParseException if the contents are invalid
* @throws IOException if there was trouble reading the contents or they are invalid
* @deprecated use {@link Schema.Parser} instead.
*/
public static Schema parse(File file) throws IOException {
Expand All @@ -1058,8 +1085,7 @@ public static Schema parse(File file) throws IOException {
* The contents of <tt>in</tt> is expected to be in UTF-8 format.
* @param in The input stream to read the schema from.
* @return The freshly built Schema.
* @throws IOException if there was trouble reading the contents
* @throws JsonParseException if the contents are invalid
* @throws IOException if there was trouble reading the contents or they are invalid
* @deprecated use {@link Schema.Parser} instead.
*/
public static Schema parse(InputStream in) throws IOException {
Expand Down Expand Up @@ -1381,12 +1407,7 @@ private static String getOptionalText(JsonNode container, String key) {
return jsonNode != null ? jsonNode.getTextValue() : null;
}

/**
* Parses a string as Json.
* @deprecated use {@link org.apache.avro.data.Json#parseJson(String)}
*/
@Deprecated
public static JsonNode parseJson(String s) {
static JsonNode parseJson(String s) {
try {
return MAPPER.readTree(FACTORY.createJsonParser(new StringReader(s)));
} catch (JsonParseException e) {
Expand All @@ -1396,6 +1417,13 @@ public static JsonNode parseJson(String s) {
}
}

/**
* Parses the specified json string to an object.
*/
public static Object parseJsonToObject(String s) {
return JacksonUtils.toObject(parseJson(s));
}

/** Rewrite a writer's schema using the aliases from a reader's schema. This
* permits reading records, enums and fixed schemas whose names have changed,
* and records whose field names have changed. The returned schema always
Expand Down
54 changes: 2 additions & 52 deletions lang/java/avro/src/main/java/org/apache/avro/data/Json.java
Expand Up @@ -62,52 +62,6 @@ private Json() {} // singleton: no public ctor
}
}

/**
* {@link DatumWriter} for arbitrary Json data.
* @deprecated use {@link ObjectWriter}
*/
@Deprecated
public static class Writer implements DatumWriter<JsonNode> {

@Override public void setSchema(Schema schema) {
if (!SCHEMA.equals(schema))
throw new RuntimeException("Not the Json schema: "+schema);
}

@Override
public void write(JsonNode datum, Encoder out) throws IOException {
Json.write(datum, out);
}
}

/**
* {@link DatumReader} for arbitrary Json data.
* @deprecated use {@link ObjectReader}
*/
@Deprecated
public static class Reader implements DatumReader<JsonNode> {
private Schema written;
private ResolvingDecoder resolver;

@Override public void setSchema(Schema schema) {
this.written = SCHEMA.equals(written) ? null : schema;
}

@Override
public JsonNode read(JsonNode reuse, Decoder in) throws IOException {
if (written == null) // same schema
return Json.read(in);

// use a resolver to adapt alternate version of Json schema
if (resolver == null)
resolver = DecoderFactory.get().resolvingDecoder(written, SCHEMA, null);
resolver.configure(in);
JsonNode result = Json.read(resolver);
resolver.drain();
return result;
}
}

/** {@link DatumWriter} for arbitrary Json data using the object model described
* in {@link org.apache.avro.JsonProperties}. */
public static class ObjectWriter implements DatumWriter<Object> {
Expand Down Expand Up @@ -176,10 +130,8 @@ private enum JsonType { LONG, DOUBLE, STRING, BOOLEAN, NULL, ARRAY, OBJECT }

/**
* Write Json data as Avro data.
* @deprecated internal method
*/
@Deprecated
public static void write(JsonNode node, Encoder out) throws IOException {
private static void write(JsonNode node, Encoder out) throws IOException {
switch(node.asToken()) {
case VALUE_NUMBER_INT:
out.writeIndex(JsonType.LONG.ordinal());
Expand Down Expand Up @@ -235,10 +187,8 @@ public static void write(JsonNode node, Encoder out) throws IOException {

/**
* Read Json data from Avro data.
* @deprecated internal method
*/
@Deprecated
public static JsonNode read(Decoder in) throws IOException {
private static JsonNode read(Decoder in) throws IOException {
switch (JsonType.values()[in.readIndex()]) {
case LONG:
return new LongNode(in.readLong());
Expand Down
Expand Up @@ -85,7 +85,7 @@ protected void validate(Field field, Object value) {
if (isValidValue(field, value)) {
return;
}
else if (field.defaultValue() != null) {
else if (field.defaultVal() != null) {
return;
}
else {
Expand Down
Expand Up @@ -47,9 +47,8 @@
import org.apache.avro.io.EncoderFactory;
import org.apache.avro.io.DatumReader;
import org.apache.avro.io.DatumWriter;
import org.apache.avro.io.parsing.ResolvingGrammarGenerator;
import org.apache.avro.util.Utf8;

import org.apache.avro.util.internal.Accessor;
import org.codehaus.jackson.JsonNode;

import com.google.common.collect.MapMaker;
Expand Down Expand Up @@ -980,7 +979,7 @@ protected int compare(Object o1, Object o2, Schema s, boolean equals) {
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public Object getDefaultValue(Field field) {
JsonNode json = field.defaultValue();
JsonNode json = Accessor.defaultValue(field);
if (json == null)
throw new AvroRuntimeException("Field " + field
+ " not set and has no default value");
Expand All @@ -1000,7 +999,7 @@ public Object getDefaultValue(Field field) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BinaryEncoder encoder = EncoderFactory.get().binaryEncoder(baos, null);
ResolvingGrammarGenerator.encode(encoder, field.schema(), json);
Accessor.encode(encoder, field.schema(), json);
encoder.flush();
BinaryDecoder decoder =
DecoderFactory.get().binaryDecoder(baos.toByteArray(), null);
Expand Down