ProtobufMapper.java
package tools.jackson.dataformat.protobuf;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Objects;
import java.util.concurrent.locks.ReentrantLock;
import tools.jackson.core.Version;
import tools.jackson.core.type.TypeReference;
import tools.jackson.databind.JavaType;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.cfg.MapperBuilder;
import tools.jackson.databind.cfg.MapperBuilderState;
import tools.jackson.dataformat.protobuf.schema.DescriptorLoader;
import tools.jackson.dataformat.protobuf.schema.FileDescriptorSet;
import tools.jackson.dataformat.protobuf.schema.ProtobufSchema;
import tools.jackson.dataformat.protobuf.schema.ProtobufSchemaLoader;
import tools.jackson.dataformat.protobuf.schemagen.ProtobufSchemaGenerator;
public class ProtobufMapper extends ObjectMapper
{
private static final long serialVersionUID = 3L;
/**
* Base implementation for "Vanilla" {@link ObjectMapper}, used with
* Protobuf backend.
*
* @since 3.0
*/
public static class Builder extends MapperBuilder<ProtobufMapper, Builder>
{
public Builder(ProtobufFactory f) {
super(f);
}
/**
* NOTE: while technically public, not intended for external use
* (since {@code StateImpl} is not public type)
*
* @param state State to restore to initialize constructed Builder
*/
@SuppressWarnings("exports")
public Builder(StateImpl state) {
super(state);
}
@Override
public ProtobufMapper build() {
return new ProtobufMapper(this);
}
@Override
protected MapperBuilderState _saveState() {
return new StateImpl(this);
}
protected static class StateImpl extends MapperBuilderState
implements java.io.Serializable // important!
{
private static final long serialVersionUID = 3L;
public StateImpl(Builder src) {
super(src);
}
// We also need actual instance of state as base class can not implement logic
// for reinstating mapper (via mapper builder) from state.
@Override
protected Object readResolve() {
return new Builder(this).build();
}
}
}
protected ProtobufSchemaLoader _schemaLoader = ProtobufSchemaLoader.std;
/**
* Lazily constructed instance of {@link DescriptorLoader}, used for loading
* structured protoc definitions from multiple files.
*/
protected volatile DescriptorLoader _descriptorLoader;
private final ReentrantLock _descriptorLock = new ReentrantLock();
/*
/**********************************************************************
/* Life-cycle
/**********************************************************************
*/
public ProtobufMapper() {
this(new ProtobufFactory());
}
public ProtobufMapper(ProtobufFactory f) {
this(new Builder(f));
}
public ProtobufMapper(Builder b) {
super(b);
}
public static Builder builder() {
return new Builder(new ProtobufFactory());
}
public static Builder builder(ProtobufFactory streamFactory) {
return new Builder(streamFactory);
}
@SuppressWarnings("unchecked")
@Override
public Builder rebuild() {
return new Builder((Builder.StateImpl) _savedBuilderState);
}
/*
/**********************************************************************
/* Life-cycle, shared "vanilla" (default configuration) instance
/**********************************************************************
*/
/**
* Accessor method for getting globally shared "default" {@link ProtobufMapper}
* instance: one that has default configuration, no modules registered, no
* config overrides. Usable mostly when dealing "untyped" or Tree-style
* content reading and writing.
*/
public static ProtobufMapper shared() {
return SharedWrapper.wrapped();
}
/*
/**********************************************************************
/* Basic accessor overrides
/**********************************************************************
*/
@Override
public Version version() {
return PackageVersion.VERSION;
}
@Override
public ProtobufFactory tokenStreamFactory() {
return (ProtobufFactory) _streamFactory;
}
/*
/**********************************************************************
/* Schema access, single protoc source
/**********************************************************************
*/
/**
* Accessor for reusable {@link ProtobufSchemaLoader} which can be
* used for loading protoc definitions from files and other external
* sources.
*/
public ProtobufSchemaLoader schemaLoader() {
return _schemaLoader;
}
public void setSchemaLoader(ProtobufSchemaLoader l) {
_schemaLoader = l;
}
/**
* Convenience method for constructing protoc definition that matches
* given Java type. Uses {@link ProtobufSchemaGenerator} for
* generation.
*
* @param type Resolved type to generate {@link ProtobufSchema} for
*
* @return Generated {@link ProtobufSchema}
*/
public ProtobufSchema generateSchemaFor(JavaType type)
{
ProtobufSchemaGenerator gen = new ProtobufSchemaGenerator();
acceptJsonFormatVisitor(type, gen);
return gen.getGeneratedSchema();
}
/**
* Convenience method for constructing protoc definition that matches
* given Java type. Uses {@link ProtobufSchemaGenerator} for generation.
*
* @param type Type-erased type to generate {@link ProtobufSchema} for
*
* @return Generated {@link ProtobufSchema}
*/
public ProtobufSchema generateSchemaFor(Class<?> type)
{
ProtobufSchemaGenerator gen = new ProtobufSchemaGenerator();
acceptJsonFormatVisitor(type, gen);
return gen.getGeneratedSchema();
}
/**
* Convenience method for constructing protoc definition that matches
* given Java type. Uses {@link ProtobufSchemaGenerator} for generation.
*
* @param type Type to generate {@link ProtobufSchema} for
*
* @return Generated {@link ProtobufSchema}
*/
public ProtobufSchema generateSchemaFor(TypeReference<?> type) {
return generateSchemaFor(_typeFactory.constructType(type));
}
/*
/**********************************************************************
/* Schema access, FileDescriptorSets
/**********************************************************************
*/
public FileDescriptorSet loadDescriptorSet(URL src) throws IOException {
return descriptorLoader().load(Objects.requireNonNull(src));
}
public FileDescriptorSet loadDescriptorSet(File src) throws IOException {
return descriptorLoader().load(Objects.requireNonNull(src));
}
public FileDescriptorSet loadDescriptorSet(InputStream src) throws IOException {
return descriptorLoader().load(Objects.requireNonNull(src));
}
/**
* Accessors that may be used instead of convenience <code>loadDescriptorSet</code>
* methods, if alternate sources need to be used.
*/
public DescriptorLoader descriptorLoader() throws IOException
{
DescriptorLoader l = _descriptorLoader;
if (l == null) {
_descriptorLock.lock();
try {
l = _descriptorLoader;
if (l == null) {
_descriptorLoader = l = DescriptorLoader.construct(this);
}
} finally {
_descriptorLock.unlock();
}
}
return l;
}
/*
/**********************************************************************
/* Helper class(es)
/**********************************************************************
*/
/**
* Helper class to contain dynamically constructed "shared" instance of
* mapper, should one be needed via {@link #shared}.
*/
private final static class SharedWrapper {
private final static ProtobufMapper MAPPER = ProtobufMapper.builder().build();
public static ProtobufMapper wrapped() { return MAPPER; }
}
}