All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ic4j.candid.jackson.JacksonDeserializer Maven / Gradle / Ivy

Go to download

Java library to serialize and deserialize Java objects to the Internet Computer Candid types.

There is a newer version: 0.7.4
Show newest version
/*
 * Copyright 2021 Exilor 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.ic4j.candid.jackson;

import java.math.BigInteger;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;

import org.ic4j.candid.CandidError;
import org.ic4j.candid.ObjectDeserializer;
import org.ic4j.candid.parser.IDLType;
import org.ic4j.candid.parser.IDLValue;
import org.ic4j.candid.types.Label;
import org.ic4j.candid.types.Type;
import org.ic4j.types.Principal;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.BigIntegerNode;
import com.fasterxml.jackson.databind.node.BinaryNode;
import com.fasterxml.jackson.databind.node.BooleanNode;
import com.fasterxml.jackson.databind.node.DoubleNode;
import com.fasterxml.jackson.databind.node.FloatNode;
import com.fasterxml.jackson.databind.node.IntNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.LongNode;
import com.fasterxml.jackson.databind.node.NullNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ShortNode;
import com.fasterxml.jackson.databind.node.TextNode;

public final class JacksonDeserializer implements ObjectDeserializer {
	Optional idlType = Optional.empty();
	ObjectMapper mapper = new ObjectMapper();	
	
	public static JacksonDeserializer create(IDLType idlType)
	{
		JacksonDeserializer deserializer = new JacksonDeserializer();
		deserializer.idlType = Optional.ofNullable(idlType);
		return deserializer;
		
	}
	
	public static JacksonDeserializer create() {
		JacksonDeserializer deserializer = new JacksonDeserializer();
		return deserializer; 
	}
	
	public void setIDLType(IDLType idlType)
	{
		this.idlType = Optional.ofNullable(idlType);
	}
	
	
	public Class getDefaultResponseClass() {
		return JsonNode.class;
	}

	@Override
	public  T deserialize(IDLValue value, Class clazz) {
		if(clazz != null)
		{
			
			
			if(JsonNode.class.isAssignableFrom(clazz))
			{
				JsonNode jsonNode = this.getValue(value.getIDLType(), this.idlType, value.getValue());
				return (T) jsonNode;
			}
			else
			{
				try {
					if(!this.idlType.isPresent())
						this.idlType = Optional.ofNullable(JacksonSerializer.getIDLType(clazz));
					
					JsonNode jsonNode = this.getValue(value.getIDLType(), this.idlType, value.getValue());
					return (T) mapper.treeToValue(jsonNode, clazz);
				} catch (JsonProcessingException | IllegalArgumentException e) {
					throw CandidError.create(CandidError.CandidErrorCode.CUSTOM,e,e.getLocalizedMessage());
				}
			}
		}
		else
			throw CandidError.create(CandidError.CandidErrorCode.CUSTOM,  "Class is not defined" );
	}
	
	JsonNode getPrimitiveValue(Type type, Object value) {
		JsonNode result = NullNode.getInstance();
		
		if(value == null)
			return result;
		
		switch(type)
		{
		case BOOL:
			result = BooleanNode.valueOf((Boolean) value);
			break;
		case INT:
			result = BigIntegerNode.valueOf((BigInteger) value);
			break;	
		case INT8:
			result = ShortNode.valueOf((Byte) value);
			break;	
		case INT16:
			result = ShortNode.valueOf((Short) value);
			break;	
		case INT32:
			result = IntNode.valueOf((Integer) value);
			break;	
		case INT64:
			result = LongNode.valueOf((Long) value);
		case NAT:
			result = BigIntegerNode.valueOf((BigInteger) value);			
			break;
		case NAT8:
			result = ShortNode.valueOf((Byte) value);
			break;	
		case NAT16:
			result = ShortNode.valueOf((Short) value);
			break;	
		case NAT32:
			result = IntNode.valueOf((Integer) value);
			break;	
		case NAT64:
			result = LongNode.valueOf((Long) value);
			break;			
		case FLOAT32:
			result = FloatNode.valueOf((Float) value);
			break;	
		case FLOAT64:
			result = DoubleNode.valueOf((Double) value);
			break;			
		case TEXT:
			result = TextNode.valueOf((String) value);
			break;
		case EMPTY:
			result = JsonNodeFactory.instance.objectNode();
			break;				
		case PRINCIPAL:
			Principal principal = (Principal) value;
			result = TextNode.valueOf(principal.toString());
			break;						
		}
		
		return result;
	}
	
	JsonNode getValue(IDLType idlType, Optional expectedIdlType, Object value) {
		JsonNode result = NullNode.getInstance();
		
		if(value == null)
			return result;		
		
		Type type = Type.NULL;
		
		if(expectedIdlType.isPresent())
		{
			type = expectedIdlType.get().getType();
			if(idlType != null)		
				idlType = expectedIdlType.get();
		}else if(idlType != null)
			type = idlType.getType();
		
		if(type.isPrimitive())
			return this.getPrimitiveValue(type,value);
		
		// handle VEC
		if(type == Type.VEC)
		{
			IDLType expectedInnerIDLType = null;
			IDLType innerIdlType = idlType.getInnerType();
			
			if(expectedIdlType.isPresent())
			{	
				expectedInnerIDLType = expectedIdlType.get().getInnerType();
				innerIdlType = expectedInnerIDLType;
			}
		
			// handle byte array
			if(innerIdlType.getType() == Type.INT8 ||innerIdlType.getType() == Type.NAT8)
				return BinaryNode.valueOf((byte[]) value);
			else 
			{						
				ArrayNode arrayNode = JsonNodeFactory.instance.arrayNode();
				
				Object[] arrayValue = (Object[]) value;
				
				for(Object item : arrayValue)
						arrayNode.add(this.getValue(idlType.getInnerType(), Optional.ofNullable(expectedInnerIDLType), item));
				
				return arrayNode;
			}
		}
		
		// handle OPT
		if(type == Type.OPT)
		{
			Optional optionalValue = (Optional) value;
			
			if(optionalValue.isPresent())
			{
				IDLType expectedInnerIDLType = null;
				
				if(expectedIdlType.isPresent())
					expectedInnerIDLType = expectedIdlType.get().getInnerType();
				
				return this.getValue(idlType.getInnerType(), Optional.ofNullable(expectedInnerIDLType), optionalValue.get());
			}
			else 
				return result;
		}
		
		
		if(type == Type.RECORD || type == Type.VARIANT)
		{
			ArrayNode arrayNode = JsonNodeFactory.instance.arrayNode();
			ObjectNode treeNode = JsonNodeFactory.instance.objectNode();
			
			Map valueMap = (Map) value;
			
			Map typeMap = idlType.getTypeMap();
			
			Map expectedTypeMap = new TreeMap();
			
			if(expectedIdlType.isPresent() && expectedIdlType.get().getTypeMap() != null)
				 expectedTypeMap = expectedIdlType.get().getTypeMap();
			
			Set




© 2015 - 2024 Weber Informatics LLC | Privacy Policy