diff --git a/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java b/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java
index a7382d0a..48cffbc7 100644
--- a/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java
+++ b/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java
@@ -90,6 +90,7 @@ public interface DataCodes {
public static final int CONTRACT_BIG_INT = 0xA07;
//...0xA19
public static final int CONTRACT_BIZ_CONTENT = 0xA20;
+ public static final int CONTRACT_ARGS = 0xA21;
public static final int HASH = 0xB00;
diff --git a/source/contract/contract-maven-plugin/pom.xml b/source/contract/contract-maven-plugin/pom.xml
index 0a357e52..626790d1 100644
--- a/source/contract/contract-maven-plugin/pom.xml
+++ b/source/contract/contract-maven-plugin/pom.xml
@@ -10,6 +10,10 @@
contract-maven-plugin
maven-plugin
+
+ 3.3.9
+
+
com.jd.blockchain
@@ -35,32 +39,54 @@
${project.version}
-
-
- org.apache.maven.plugin-tools
- maven-plugin-annotations
- 3.6.0
- provided
+ com.github.javaparser
+ javaparser-core
+ ${javaparser.version}
+
org.apache.maven
maven-plugin-api
- 2.0
+ 3.3.9
org.apache.maven
- maven-project
- 2.0.6
+ maven-core
+ 3.3.9
-
- com.github.javaparser
- javaparser-core
- ${javaparser.version}
+ org.apache.maven
+ maven-artifact
+ 3.3.9
+ provided
+
+
+ org.apache.maven
+ maven-compat
+ 3.3.9
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+ org.apache.maven.plugin-testing
+ maven-plugin-testing-harness
+ test
+ 3.3.0
+
+
+ org.apache.maven.plugin-tools
+ maven-plugin-annotations
+ 3.6.0
+ provided
+
diff --git a/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/CheckImportsMojo.java b/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/CheckImportsMojo.java
index 7c62b31c..64a12e20 100644
--- a/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/CheckImportsMojo.java
+++ b/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/CheckImportsMojo.java
@@ -4,6 +4,12 @@ import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.PackageDeclaration;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
+import com.jd.blockchain.transaction.ContractType;
+import com.jd.blockchain.utils.IllegalDataException;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
@@ -12,15 +18,28 @@ import org.apache.maven.project.MavenProject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.net.URL;
+import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Properties;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
import java.util.stream.Collectors;
-
+/**
+ * first step, we want to parse the source code by javaParse. But it's repeated and difficult to parse the source.
+ * This is a try of "from Initail to Abandoned".
+ * Since we are good at the class, why not?
+ * Now we change a way of thinking, first we pre-compile the source code, then parse the *.jar.
+ *
+ * by zhaogw
+ * date 2019-06-05 16:17
+ */
@Mojo(name = "checkImports")
public class CheckImportsMojo extends AbstractMojo {
Logger logger = LoggerFactory.getLogger(CheckImportsMojo.class);
@@ -28,6 +47,12 @@ public class CheckImportsMojo extends AbstractMojo {
@Parameter(defaultValue = "${project}", required = true, readonly = true)
private MavenProject project;
+ /**
+ * jar's name;
+ */
+ @Parameter
+ private String finalName;
+
@Override
public void execute() throws MojoFailureException {
List sources;
@@ -40,6 +65,9 @@ public class CheckImportsMojo extends AbstractMojo {
sources = Files.find(baseDirPath, Integer.MAX_VALUE, (file, attrs) -> (file.toString().endsWith(".java"))).collect(Collectors.toList());
for (Path path : sources) {
CompilationUnit compilationUnit = JavaParser.parse(path);
+
+ compilationUnit.accept(new MethodVisitor(), null);
+
NodeList imports = compilationUnit.getImports();
for (ImportDeclaration imp : imports) {
String importName = imp.getName().asString();
@@ -49,6 +77,20 @@ public class CheckImportsMojo extends AbstractMojo {
}
}
}
+
+ //now we parse the jar;
+ String jarPath = project.getBuild().getDirectory()+ File.separator+finalName+".jar";
+ File jarFile = new File(jarPath);
+ URL jarURL = jarFile.toURI().toURL();
+ ClassLoader classLoader = new URLClassLoader(new URL[]{jarURL},this.getClass().getClassLoader());
+ Attributes m = new JarFile(jarFile).getManifest().getMainAttributes();
+ String contractMainClass = m.getValue(Attributes.Name.MAIN_CLASS);
+ try {
+ Class mainClass = classLoader.loadClass(contractMainClass);
+ ContractType.resolve(mainClass);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalDataException(e.getMessage());
+ }
}
} catch (IOException exception) {
logger.error(exception.getMessage());
@@ -57,4 +99,29 @@ public class CheckImportsMojo extends AbstractMojo {
logger.error(e.getMessage());
}
}
+
+ private class MethodVisitor extends VoidVisitorAdapter {
+ @Override
+ public void visit(MethodDeclaration n, Void arg) {
+ /* here you can access the attributes of the method.
+ this method will be called for all methods in this
+ CompilationUnit, including inner class methods */
+ logger.info("method:"+n.getName());
+ super.visit(n, arg);
+ }
+
+ @Override
+ public void visit(ClassOrInterfaceDeclaration n, Void arg) {
+ logger.info("class:"+n.getName()+" extends:"+n.getExtendedTypes()+" implements:"+n.getImplementedTypes());
+
+ super.visit(n, arg);
+ }
+
+ @Override
+ public void visit(PackageDeclaration n, Void arg) {
+ logger.info("package:"+n.getName());
+ super.visit(n, arg);
+ }
+
+ }
}
diff --git a/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/CheckImportsMojoTest.java b/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/CheckImportsMojoTest.java
index 9a91e4f6..66b194c0 100644
--- a/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/CheckImportsMojoTest.java
+++ b/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/CheckImportsMojoTest.java
@@ -1,32 +1,28 @@
package com.jd.blockchain.ledger;
import com.jd.blockchain.CheckImportsMojo;
+import org.apache.maven.plugin.testing.AbstractMojoTestCase;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.Properties;
+import java.io.File;
/**
* @Author zhaogw
* @Date 2019/3/1 21:27
*/
-public class CheckImportsMojoTest {
- Logger logger = LoggerFactory.getLogger(CheckImportsMojo.class);
+public class CheckImportsMojoTest extends AbstractMojoTestCase {
+ Logger logger = LoggerFactory.getLogger(CheckImportsMojoTest.class);
@Test
- public void test1() {
- try {
- InputStream inputStream = CheckImportsMojo.class.getClassLoader().getResourceAsStream("config.properties");
- Properties properties = new Properties();
- properties.load(inputStream);
- String result[] = properties.getProperty("blacklist").split(",");
- logger.info(Arrays.toString(result).toString());
- } catch (IOException e) {
- logger.error(e.getMessage());
- }
+ public void test1() throws Exception {
+ File pom = getTestFile( "src/test/resources/project-to-test/pom.xml" );
+ assertNotNull( pom );
+ assertTrue( pom.exists() );
+
+ CheckImportsMojo myMojo = (CheckImportsMojo) lookupMojo( "checkImports", pom );
+ assertNotNull( myMojo );
+ myMojo.execute();
}
}
diff --git a/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractDeployMojoTest.java b/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractDeployMojoTest.java
index 85c02021..0d205758 100644
--- a/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractDeployMojoTest.java
+++ b/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractDeployMojoTest.java
@@ -1,10 +1,8 @@
package com.jd.blockchain.ledger;
import com.jd.blockchain.ContractDeployMojo;
-import org.junit.Test;
import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
/**
* for contract deploy and exe;
@@ -14,8 +12,7 @@ import java.lang.reflect.InvocationTargetException;
public class ContractDeployMojoTest {
private ContractDeployMojo contractDeployMojo = new ContractDeployMojo();
- private void fieldHandle(String fieldName,Object objValue) throws NoSuchFieldException,
- IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException {
+ private void fieldHandle(String fieldName,Object objValue) throws NoSuchFieldException, IllegalAccessException {
Field field = contractDeployMojo.getClass().getDeclaredField(fieldName);//name为类Instance中的private属性
field.setAccessible(true);//=true,可访问私有变量。
Class> typeClass = field.getType();
diff --git a/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/MyProjectStub.java b/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/MyProjectStub.java
new file mode 100644
index 00000000..473115af
--- /dev/null
+++ b/source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/MyProjectStub.java
@@ -0,0 +1,67 @@
+package com.jd.blockchain.ledger;
+
+import org.apache.maven.model.Build;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
+import org.apache.maven.plugin.testing.stubs.MavenProjectStub;
+import org.codehaus.plexus.util.ReaderFactory;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author zhaogw
+ * date 2019/6/4 18:33
+ */
+
+public class MyProjectStub extends MavenProjectStub
+{
+ /**
+ * Default constructor
+ */
+ public MyProjectStub()
+ {
+ MavenXpp3Reader pomReader = new MavenXpp3Reader();
+ Model model;
+ try
+ {
+ model = pomReader.read( ReaderFactory.newXmlReader( new File( getBasedir(), "pom.xml" ) ) );
+ setModel( model );
+ }
+ catch ( Exception e )
+ {
+ throw new RuntimeException( e );
+ }
+
+ setGroupId( model.getGroupId() );
+ setArtifactId( model.getArtifactId() );
+ setVersion( model.getVersion() );
+ setName( model.getName() );
+ setUrl( model.getUrl() );
+ setPackaging( model.getPackaging() );
+
+ Build build = new Build();
+ build.setFinalName( model.getArtifactId() );
+ build.setDirectory( getBasedir() + "/target" );
+ build.setSourceDirectory( getBasedir() + "/src/main/java" );
+ build.setOutputDirectory( getBasedir() + "/target/classes" );
+ build.setTestSourceDirectory( getBasedir() + "/src/test/java" );
+ build.setTestOutputDirectory( getBasedir() + "/target/test-classes" );
+ setBuild( build );
+
+ List compileSourceRoots = new ArrayList();
+ compileSourceRoots.add( getBasedir() + "/src/main/java" );
+ setCompileSourceRoots( compileSourceRoots );
+
+ List testCompileSourceRoots = new ArrayList();
+ testCompileSourceRoots.add( getBasedir() + "/src/test/java" );
+ setTestCompileSourceRoots( testCompileSourceRoots );
+ }
+
+ /** {@inheritDoc} */
+ public File getBasedir()
+ {
+ return new File( super.getBasedir() + "/src/test/resources/project-to-test/" );
+ }
+}
diff --git a/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContract2.java b/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContract2.java
new file mode 100644
index 00000000..b597558e
--- /dev/null
+++ b/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContract2.java
@@ -0,0 +1,40 @@
+package com.jd.blockchain.contract;
+
+import com.jd.blockchain.ledger.ContractBizContent;
+import com.jd.blockchain.utils.Bytes;
+
+/**
+ * 示例:一个“资产管理”智能合约;
+ *
+ * @author zhaogw
+ */
+@Contract
+public interface AssetContract2 {
+
+ /**
+ * 发行资产;
+ * 新发行的资产数量;
+ * @param assetHolderAddress
+ * 新发行的资产的持有账户;
+ */
+ @ContractEvent(name = "issue-asset-0")
+ void issue(ContractBizContent contractBizContent, String assetHolderAddress);
+
+ /**
+ * 发行资产;
+ * 新发行的资产数量;
+ * @param assetHolderAddress
+ * 新发行的资产的持有账户;
+ */
+ @ContractEvent(name = "issue-asset")
+ void issue(ContractBizContent contractBizContent, String assetHolderAddress, long cashNumber);
+
+ @ContractEvent(name = "issue-asset-2")
+ void issue(Bytes bytes, String assetHolderAddress, long cashNumber);
+
+ @ContractEvent(name = "issue-asset-3")
+ void issue(Byte byteObj, String assetHolderAddress, long cashNumber);
+
+ @ContractEvent(name = "issue-asset-4")
+ void issue(Byte byteObj, String assetHolderAddress, Bytes cashNumber);
+}
\ No newline at end of file
diff --git a/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContractImpl2.java b/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContractImpl2.java
new file mode 100644
index 00000000..06af2632
--- /dev/null
+++ b/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContractImpl2.java
@@ -0,0 +1,99 @@
+package com.jd.blockchain.contract;
+
+import com.jd.blockchain.ledger.ContractBizContent;
+import com.jd.blockchain.ledger.KVDataEntry;
+import com.jd.blockchain.ledger.KVDataObject;
+import com.jd.blockchain.utils.Bytes;
+
+import java.util.Arrays;
+
+/**
+ * 示例:一个“资产管理”智能合约的实现;
+ *
+ * 注: 1、实现 EventProcessingAwire 接口以便合约实例在运行时可以从上下文获得合约生命周期事件的通知; 2、实现
+ * AssetContract 接口定义的合约方法;
+ *
+ * @author huanghaiquan
+ *
+ */
+@Contract
+public class AssetContractImpl2 implements EventProcessingAwire, AssetContract2 {
+ public static String KEY_TOTAL = "total";
+ // 合约事件上下文;
+ private ContractEventContext eventContext;
+
+ @Override
+ @ContractEvent(name = "issue-asset-0")
+ public void issue(ContractBizContent contractBizContent, String assetHolderAddress) {
+ System.out.println("input addr="+ Arrays.toString(contractBizContent.getAttrs()));
+ }
+
+ @Override
+ @ContractEvent(name = "issue-asset")
+ public void issue(ContractBizContent contractBizContent, String assetHolderAddress, long cashNumber) {
+ System.out.println("eventContext="+eventContext.getCurrentLedgerHash().toBase58());
+ System.out.println("getAttrs: "+Arrays.toString(contractBizContent.getAttrs())+",address="+assetHolderAddress+",cashNumber="+cashNumber);
+
+ eventContext.getLedger().dataAccount(assetHolderAddress).set(contractBizContent.getAttrs()[0], "value1",-1);
+ eventContext.getLedger().dataAccount(assetHolderAddress).set(contractBizContent.getAttrs()[1], 888,-1);
+ }
+
+ @Override
+ @ContractEvent(name = "issue-asset-2")
+ public void issue(Bytes bytes, String assetHolderAddress, long cashNumber){
+ System.out.println(String.format("bytes=%s,assetHolderAddress=%s,cashNumber=%d",new String(bytes.toBytes()),assetHolderAddress,cashNumber));
+ }
+
+ @ContractEvent(name = "issue-asset-3")
+ @Override
+ public void issue(Byte byteObj, String assetHolderAddress, long cashNumber) {
+ System.out.println(String.format("issue(),bytes=%d,assetHolderAddress=%s,cashNumber=%d",byteObj.intValue(),assetHolderAddress,cashNumber));
+ }
+
+ @ContractEvent(name = "issue-asset-4")
+ @Override
+ public void issue(Byte byteObj, String assetHolderAddress, Bytes cashNumber) {
+ System.out.println(String.format("issue(),bytes=%d,assetHolderAddress=%s,cashNumber=%s",byteObj.intValue(),assetHolderAddress,cashNumber.toString()));
+ System.out.println("current LedgerHash="+eventContext.getCurrentLedgerHash().toBase58());
+ // 查询当前值;
+ KVDataEntry[] kvEntries = eventContext.getLedger().getDataEntries(eventContext.getCurrentLedgerHash(), assetHolderAddress, KEY_TOTAL);
+// 计算资产的发行总数;
+ KVDataObject curTotal = (KVDataObject) kvEntries[0];
+ System.out.println("currTotal version="+curTotal.getVersion()+",value="+curTotal.getValue().toString());
+ eventContext.getLedger().dataAccount(assetHolderAddress).set(KEY_TOTAL, 100,curTotal.getVersion());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.jd.blockchain.contract.model.EventProcessingAwire#beforeEvent(com.jd.
+ * blockchain.contract.model.ContractEventContext)
+ */
+ @Override
+ public void beforeEvent(ContractEventContext eventContext) {
+ this.eventContext = eventContext;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.jd.blockchain.contract.model.EventProcessingAwire#postEvent(com.jd.
+ * blockchain.contract.model.ContractEventContext,
+ * com.jd.blockchain.contract.model.ContractError)
+ */
+ @Override
+ public void postEvent(ContractEventContext eventContext, ContractException error) {
+ this.eventContext = null;
+ }
+
+ @Override
+ public void postEvent(ContractException error) {
+
+ }
+
+ @Override
+ public void postEvent() {
+
+ }
+}
diff --git a/source/contract/contract-maven-plugin/src/test/resources/project-to-test/pom.xml b/source/contract/contract-maven-plugin/src/test/resources/project-to-test/pom.xml
new file mode 100644
index 00000000..ea7962e8
--- /dev/null
+++ b/source/contract/contract-maven-plugin/src/test/resources/project-to-test/pom.xml
@@ -0,0 +1,24 @@
+
+ 4.0.0
+
+ com.jd.blockchain
+ project-to-test
+ 1.0-SNAPSHOT
+ jar
+ Test MyMojo
+
+
+
+
+ contract-maven-plugin
+
+
+
+
+ contract1
+
+
+
+
+
\ No newline at end of file
diff --git a/source/contract/contract-maven-plugin/src/test/resources/project-to-test/target/contract.jar b/source/contract/contract-maven-plugin/src/test/resources/project-to-test/target/contract.jar
new file mode 100644
index 00000000..7c172d0e
Binary files /dev/null and b/source/contract/contract-maven-plugin/src/test/resources/project-to-test/target/contract.jar differ
diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractArgs.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractArgs.java
new file mode 100644
index 00000000..9cce0cee
--- /dev/null
+++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractArgs.java
@@ -0,0 +1,14 @@
+package com.jd.blockchain.ledger;
+import com.jd.blockchain.binaryproto.DataContract;
+import com.jd.blockchain.consts.DataCodes;
+
+import java.lang.reflect.Method;
+
+/**
+ * contract's args;
+ */
+@DataContract(code = DataCodes.CONTRACT_ARGS)
+public interface ContractArgs {
+ Method getMethod();
+ Object[] getArgs();
+}
diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/DataAccountKVSetOperationBuilderImpl.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/DataAccountKVSetOperationBuilderImpl.java
index c0511e55..537efdf7 100644
--- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/DataAccountKVSetOperationBuilderImpl.java
+++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/DataAccountKVSetOperationBuilderImpl.java
@@ -32,10 +32,10 @@ public class DataAccountKVSetOperationBuilderImpl implements DataAccountKVSetOpe
public DataAccountKVSetOperationBuilder set(String key, String value, long expVersion) {
BytesValue bytesValue;
if (JSONSerializeUtils.isJSON(value)) {
- bytesValue = new BytesValueEntry(BytesValueType.JSON, value.getBytes());
+ bytesValue = new BytesValueEntry(BytesValueType.JSON, BytesUtils.toBytes(value));
}
else {
- bytesValue = new BytesValueEntry(BytesValueType.TEXT, value.getBytes());
+ bytesValue = new BytesValueEntry(BytesValueType.TEXT, BytesUtils.toBytes(value));
}
operation.set(key, bytesValue, expVersion);
return this;
diff --git a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java
index 359b4dd4..9a1ff31d 100644
--- a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java
+++ b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java
@@ -18,10 +18,12 @@ import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
+import org.springframework.util.ReflectionUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
+import java.lang.reflect.Method;
import static org.junit.Assert.*;
@@ -351,4 +353,24 @@ public class SDK_Contract_Test {
ContractBizContent actualObj = BinaryProtocol.decodeAs(bizBytes,ContractBizContent.class);
assertArrayEquals(contractBizContent.getAttrs(),actualObj.getAttrs());
}
+
+ @Test
+ public void testContractArgs(){
+ ContractBizContent contractBizContent = () -> new String[]{"param1"};
+ Method method = ReflectionUtils.findMethod(AssetContract2.class,"issue",ContractBizContent.class,String.class);
+ ContractArgs contractArgs = new ContractArgs() {
+ @Override
+ public Method getMethod() {
+ return method;
+ }
+
+ @Override
+ public Object[] getArgs() {
+ return new Object[]{contractBizContent,"hello"};
+ }
+ };
+
+ //add the annotation;
+
+ }
}