{"id":52139,"date":"2025-06-05T00:00:00","date_gmt":"2025-06-05T07:00:00","guid":{"rendered":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/blog\/griddb-sonarqube-integration\/"},"modified":"2025-06-05T00:00:00","modified_gmt":"2025-06-05T07:00:00","slug":"griddb-sonarqube-integration","status":"publish","type":"post","link":"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/","title":{"rendered":"Griddb SonarQube Integration"},"content":{"rendered":"<h2><strong>Introduction<\/strong><\/h2>\n<p><a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a> is widely used for continuous code quality inspection, helping teams detect bugs and vulnerabilities early. However, as projects scale, the backend database can become a bottleneck, affecting performance. Integrating GridDB, a high-performance, distributed NoSQL database, with <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a> enhances its data processing capabilities, providing faster insights and better scalability for large projects.<\/p>\n<p>This blog will explore how integrating <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a> with GridDB can help teams monitor and improve code quality over time. We will provide a step-by-step guide to set up this integration and demonstrate its benefits in achieving a more efficient and high-quality development process.<\/p>\n<p><strong>Why Use GridDB with <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a>?<\/strong><\/p>\n<p>While <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a> is a powerful tool for static code analysis, it has limitations when it comes to long-term data storage and real-time analytics:<\/p>\n<ul>\n<li><strong>Limited Data Retention:<\/strong> <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a>&#8216;s built-in database may not be optimized for long-term storage of historical code quality data.<\/li>\n<li><strong>Performance Bottlenecks:<\/strong> As the volume of data grows, <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a>&#8216;s performance may degrade, especially when querying historical trends.<\/li>\n<li><strong>Lack of Real-time Analytics:<\/strong> <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a> primarily focuses on static analysis and may not provide real-time insights into code quality metrics.<\/li>\n<\/ul>\n<p><strong>By integrating <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a> with GridDB, we can:<\/strong><\/p>\n<ul>\n<li><strong>Enhance data retention:<\/strong> Store historical code quality data for long-term analysis.<\/li>\n<li><strong>Improve performance:<\/strong> Accelerate query performance and enable real-time insights.<\/li>\n<li><strong>Gain deeper insights:<\/strong> Analyze trends, identify recurring issues, and measure the impact of code improvements.<\/li>\n<li><strong>Make data-driven decisions:<\/strong> Use historical data to optimize development processes and prioritize code quality initiatives.<\/li>\n<\/ul>\n<h2>Setting Up GridDB Cluster and Spring Boot Integration: For Real-Time Monitoring<\/h2>\n<p>The first step is to set up a GridDB cluster and integrate it with our Spring Boot application as follows.<\/p>\n<ul>\n<li><strong>Setting up GridDB Cluster<\/strong><\/li>\n<\/ul>\n<p>GridDB provides flexible options to meet different requirements. For development, a single-node cluster on our local machine may be sufficient. However, in production, distributed clusters across multiple machines are typically preferred for improved fault tolerance and scalability. For detailed guidance on setting up clusters based on our deployment strategy, refer to the GridDB documentation.<\/p>\n<p>To set up a GridDB cluster, follow the steps mentioned <a href=\"https:\/\/docs.griddb.net\/gettingstarted\/using-apt\/#install-with-apt-get\">here<\/a>.<\/p>\n<ul>\n<li><strong>Setting up SonarCluster<\/strong><\/li>\n<\/ul>\n<p>We can either use an existing <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a> instance or, for evaluation purposes, set up a <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a> instance using Docker as shown below.<\/p>\n<ol>\n<li>\n<p><em>Pull Image<\/em><\/p>\n<p><code>docker run -d --name [SonarQube](https:\/\/www.sonarsource.com\/) -p 9000:9000 [SonarQube](https:\/\/www.sonarsource.com\/):latest<\/code><\/p>\n<p>This will pull the latest <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a> image and run it on port 9000. You can access the <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a> dashboard by navigating to <code>http:\/\/localhost:9000<\/code> in your browser.<\/p>\n<\/li>\n<li>\n<p><em>Access <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a>:<\/em><br \/>\nOnce the container is running, open a browser and go to <code>http:\/\/localhost:9000<\/code>. The default login credentials are:<\/p>\n<\/li>\n<\/ol>\n<ul>\n<li><strong>Username<\/strong>: <code>admin<\/code><\/li>\n<li><strong>Password<\/strong>: <code>admin<\/code><\/li>\n<\/ul>\n<ol>\n<li><em>Create an API Access Token:<\/em><\/li>\n<\/ol>\n<ul>\n<li>Log in to the <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a> dashboard.<\/li>\n<li>Navigate to <strong>My Account<\/strong> by clicking on your username at the top right.<\/li>\n<li>Go to the <strong>Security<\/strong> tab.<\/li>\n<li>Under the <strong>Tokens<\/strong> section, click on <strong>Generate Token<\/strong>.<\/li>\n<li>Enter a name for the token (e.g., &#8220;API Access&#8221;) and click <strong>Generate<\/strong>.<\/li>\n<li>Copy the generated token as it will not be shown again.\n<ul>\n<li><strong>Setting up Spring Boot Application<\/strong><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Once our GridDB cluster is operational, the next step is connecting it to ourSpring Boot application. The GridDB Java Client API provides the necessary tools to establish this connection. To simplify the process, you can include the <code>griddb-spring-boot-starter<\/code> library as a dependency in our project, which offers pre-configured beans for a streamlined connection setup.<\/p>\n<p><strong>Project Structure<\/strong><\/p>\n<p>Here&#8217;s a suggested project structure for such an application:<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">my-griddb-app\n    \u2502   pom.xml\n    \u2502   \n    \u251c\u2500\u2500\u2500src\n    \u2502   \u251c\u2500\u2500\u2500main\n    \u2502   \u2502   \u251c\u2500\u2500\u2500java\n    \u2502   \u2502   \u2502   \u2514\u2500\u2500\u2500mycode\n    \u2502   \u2502   \u2502       \u2502   MySpringBootApplication.java\n    \u2502   \u2502   \u2502       \u2502   \n    \u2502   \u2502   \u2502       \u251c\u2500\u2500\u2500config\n    \u2502   \u2502   \u2502       \u2502       GridDBConfig.java\n    \u2502   \u2502   \u2502       \u2502       \n    \u2502   \u2502   \u2502       \u251c\u2500\u2500\u2500controller\n    \u2502   \u2502   \u2502       \u2502       ChartController.java\n    \u2502   \u2502   \u2502       \u2502       \n    \u2502   \u2502   \u2502       \u251c\u2500\u2500\u2500dto\n    \u2502   \u2502   \u2502       \u2502       SonarMetricDTO.java\n    \u2502   \u2502   \u2502       \u2502       \n    \u2502   \u2502   \u2502       \u2514\u2500\u2500\u2500service\n    \u2502   \u2502   \u2502               ChartService.java\n    \u2502   \u2502   \u2502               MetricsCollectionService.java\n    \u2502   \u2502   \u2502               RestTemplateConfig.java\n    \u2502   \u2502   \u2502\n    \u2502   \u2502   \u2514\u2500\u2500\u2500resources\n    \u2502   \u2502       \u2502   application.properties\n    \u2502   \u2502       \u2502\n    \u2502   \u2502       \u2514\u2500\u2500\u2500templates\n    \u2502   \u2502               charts.html<\/code><\/pre>\n<\/div>\n<p>This structure separates controllers, models, repositories, services, and the application entry point into distinct layers, enhancing modularity and maintainability.<\/p>\n<p><strong>Add GridDB Dependency<\/strong><\/p>\n<p>To enable interaction with GridDB in our Spring Boot project, we must include the GridDB Java Client API dependency. This can be accomplished by adding the appropriate configuration to the project build file, such as <code>pom.xml<\/code> for Maven or the equivalent file for Gradle.<\/p>\n<p>Here&#8217;s an example of how to configure the dependency in the<code>pom.xml<\/code> file:<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">&lt;project \n  xmlns_xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\n  xsi_schemaLocation=\"http:\/\/maven.apache.org\/POM\/4.0.0 http:\/\/maven.apache.org\/maven-v4_0_0.xsd\"&gt;\n  &lt;modelVersion&gt;4.0.0&lt;\/modelVersion&gt;\n  &lt;groupId&gt;com.example&lt;\/groupId&gt;\n  &lt;artifactId&gt;my-griddb-app&lt;\/artifactId&gt;\n  &lt;version&gt;1.0-SNAPSHOT&lt;\/version&gt;\n  &lt;name&gt;my-griddb-app&lt;\/name&gt;\n  &lt;url&gt;http:\/\/maven.apache.org&lt;\/url&gt;\n\n  &lt;parent&gt;\n    &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n    &lt;artifactId&gt;spring-boot-starter-parent&lt;\/artifactId&gt;\n    &lt;version&gt;3.2.4&lt;\/version&gt;\n    &lt;relativePath \/&gt; &lt;!-- lookup parent from repository --&gt;\n  &lt;\/parent&gt;\n\n  &lt;properties&gt;\n    &lt;maven.compiler.source&gt;17&lt;\/maven.compiler.source&gt;\n    &lt;maven.compiler.target&gt;17&lt;\/maven.compiler.target&gt;\n  &lt;\/properties&gt;\n\n  &lt;dependencies&gt;\n    &lt;dependency&gt;\n      &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n      &lt;artifactId&gt;spring-boot-starter-actuator&lt;\/artifactId&gt;\n    &lt;\/dependency&gt;\n    &lt;dependency&gt;\n      &lt;groupId&gt;junit&lt;\/groupId&gt;\n      &lt;artifactId&gt;junit&lt;\/artifactId&gt;\n      &lt;version&gt;3.8.1&lt;\/version&gt;\n      &lt;scope&gt;test&lt;\/scope&gt;\n    &lt;\/dependency&gt;\n    &lt;!-- GridDB dependencies --&gt;\n    &lt;dependency&gt;\n      &lt;groupId&gt;com.github.griddb&lt;\/groupId&gt;\n      &lt;artifactId&gt;gridstore&lt;\/artifactId&gt;\n      &lt;version&gt;5.6.0&lt;\/version&gt;\n    &lt;\/dependency&gt;\n    &lt;!-- Spring Boot dependencies --&gt;\n    &lt;dependency&gt;\n      &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n      &lt;artifactId&gt;spring-boot-starter-web&lt;\/artifactId&gt;\n      &lt;exclusions&gt;\n        &lt;exclusion&gt;\n          &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n          &lt;artifactId&gt;spring-boot-starter-logging&lt;\/artifactId&gt;\n        &lt;\/exclusion&gt;\n      &lt;\/exclusions&gt;\n    &lt;\/dependency&gt;\n    &lt;dependency&gt;\n      &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n      &lt;artifactId&gt;spring-boot-starter-test&lt;\/artifactId&gt;\n      &lt;scope&gt;test&lt;\/scope&gt;\n    &lt;\/dependency&gt;\n    &lt;dependency&gt;\n      &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n      &lt;artifactId&gt;spring-boot-starter-thymeleaf&lt;\/artifactId&gt;\n    &lt;\/dependency&gt;\n    &lt;!-- JSON processing --&gt;\n    &lt;dependency&gt;\n      &lt;groupId&gt;com.fasterxml.jackson.core&lt;\/groupId&gt;\n      &lt;artifactId&gt;jackson-databind&lt;\/artifactId&gt;\n      &lt;version&gt;2.15.0&lt;\/version&gt; &lt;!-- or the latest version --&gt;\n    &lt;\/dependency&gt;\n    &lt;!-- Lombok --&gt;\n    &lt;dependency&gt;\n      &lt;groupId&gt;org.projectlombok&lt;\/groupId&gt;\n      &lt;artifactId&gt;lombok&lt;\/artifactId&gt;\n      &lt;optional&gt;true&lt;\/optional&gt;\n    &lt;\/dependency&gt;\n  &lt;\/dependencies&gt;\n&lt;\/project&gt;<\/code><\/pre>\n<\/div>\n<p><strong>Configure GridDB Connection<\/strong><\/p>\n<p>After adding the GridDB dependency, the next step is configuring the connection details for our GridDB cluster in our Spring Boot application. This is usually configured in the <code>application.properties<\/code> file, where you can specify various settings for the application.<\/p>\n<p>Here\u2019s a quick example of how to set up those connection details:<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">GRIDDB_NOTIFICATION_MEMBER=127.0.0.1:10001\nGRIDDB_CLUSTER_NAME=myCluster\nGRIDDB_USER=admin\nGRIDDB_PASSWORD=admin\nmanagement.endpoints.web.exposure.include=*\nserver.port=9090\n\n# [SonarQube](https:\/\/www.sonarsource.com\/) Configuration\nsonar.url=http:\/\/localhost:9000\nsonar.token=squ_06bfcd665f7ca4115d9d230b0fe19f294246c919\nsonar.projectKey=Helloworld\nsonar.metricKeys=coverage,duplicated_lines_density,code_smells,bugs,vulnerabilities,complexity,ncloc,comment_lines,lines,functions,classes,files<\/code><\/pre>\n<\/div>\n<ul>\n<li><code>griddb.cluster.host<\/code>: The hostname or IP address of ourGridDB cluster.<\/li>\n<li><code>griddb.cluster.port<\/code>: The port number on which the GridDB cluster is listening.<\/li>\n<li><code>griddb.cluster.user<\/code>: The username for accessing the GridDB cluster.<\/li>\n<li><code>griddb.cluster.password<\/code>: The password for the specified GridDB user (replace with ouractual password).<\/li>\n<li><code>server.port=9090<\/code>: Sets the port on which ourSpring Boot application will run.<\/li>\n<li><code>sonar.projectKey<\/code>: This property uniquely identifies your project within <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a>.<\/li>\n<\/ul>\n<p><strong>Create GridDB Client Bean<\/strong><\/p>\n<p>To interact effectively with GridDB in our Spring Boot application,we need to create a dedicated Spring Bean to manage the GridDB connection. This bean will establish the connection using the parameters defined in the <code>application.properties<\/code> file and will act as the central interface for interacting with the GridDB cluster across the application.<\/p>\n<p>Here&#8217;s an example of how to define this bean in a Java class named <code>GridDbConfig.java<\/code>:<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-java\">package mycode.config;\n\nimport java.util.Properties;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.PropertySource;\n\nimport com.toshiba.mwcloud.gs.GSException;\nimport com.toshiba.mwcloud.gs.GridStore;\nimport com.toshiba.mwcloud.gs.GridStoreFactory;\n\n@Configuration\n@PropertySource(\"classpath:application.properties\")\npublic class GridDBConfig {\n\n @Value(\"${GRIDDB_NOTIFICATION_MEMBER}\")\n\u00a0 private String notificationMember;\n\n @Value(\"${GRIDDB_CLUSTER_NAME}\")\n\u00a0 private String clusterName;\n\n @Value(\"${GRIDDB_USER}\")\n\u00a0 private String user;\n\n @Value(\"${GRIDDB_PASSWORD}\")\n\u00a0 private String password;\n\n @Bean\n\u00a0 public GridStore gridStore() throws GSException {\n\u00a0 \u00a0 \/\/ Acquiring a GridStore instance\n\u00a0 \u00a0 Properties properties = new Properties();\n\u00a0 \u00a0 properties.setProperty(\"notificationMember\", notificationMember);\n\u00a0 \u00a0 properties.setProperty(\"clusterName\", clusterName);\n\u00a0 \u00a0 properties.setProperty(\"user\", user);\n\u00a0 \u00a0 properties.setProperty(\"password\", password);\n\u00a0 \u00a0 return GridStoreFactory.getInstance().getGridStore(properties);\n }\n}<\/code><\/pre>\n<\/div>\n<h2>Metric Collection<\/h2>\n<p>In this section, we&#8217;ll delve into the technical flow of how <strong><a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a><\/strong> collects code quality metrics and how these metrics can be transferred and stored in <strong>GridDB<\/strong> for analysis.<\/p>\n<h4>1. <strong>Extracting Metrics from <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a><\/strong><\/h4>\n<p><a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a> provides a comprehensive set of code quality metrics that can be accessed via its API. These metrics include:<\/p>\n<ul>\n<li><strong>Bugs<\/strong>: Issues in the code that could lead to system malfunctions.<\/li>\n<li><strong>Code Smells<\/strong>: Pieces of code that may not be erroneous but could negatively affect readability and maintainability.<\/li>\n<li><strong>Vulnerabilities<\/strong>: Security-related issues that could make the application susceptible to exploits.<\/li>\n<li><strong>Test Coverage<\/strong>: The percentage of code covered by automated tests.<\/li>\n<li><strong>Duplications<\/strong>: The extent of redundant code across the project.<\/li>\n<\/ul>\n<p>The process to retrieve these metrics involves making HTTP requests to specific <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a> API endpoints. For instance:<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">GET \/api\/measures\/component?component=<project_key>&metricKeys=<metric_1>,<metric_2><\/code><\/pre>\n<\/div>\n<h4><strong>API Request Example<\/strong><\/h4>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">GET \/api\/measures\/component?component=project_xyz&metricKeys=bugs,coverage<\/code><\/pre>\n<\/div>\n<h4><strong>API Response<\/strong><\/h4>\n<p>The API responds with the metrics in JSON format, typically including a list of measures. For example:<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">{\n    \"component\": {\n        \"key\": \"Helloworld\",\n        \"name\": \"Helloworld\",\n        \"description\": \"A simple Spring Boot 2.x app to send hello world message to a user\",\n        \"qualifier\": \"TRK\",\n        \"measures\": [\n            {\n                \"metric\": \"duplicated_lines_density\",\n                \"value\": \"0.0\",\n                \"bestValue\": true\n            },\n            {\n                \"metric\": \"classes\",\n                \"value\": \"2\"\n            },\n            {\n                \"metric\": \"functions\",\n                \"value\": \"18\"\n            },\n            {\n                \"metric\": \"lines\",\n                \"value\": \"211\"\n            },\n            {\n                \"metric\": \"coverage\",\n                \"value\": \"0.0\",\n                \"bestValue\": false\n            },\n            {\n                \"metric\": \"ncloc\",\n                \"value\": \"160\"\n            },\n            {\n                \"metric\": \"files\",\n                \"value\": \"3\"\n            },\n            {\n                \"metric\": \"vulnerabilities\",\n                \"value\": \"0\",\n                \"bestValue\": true\n            },\n            {\n                \"metric\": \"bugs\",\n                \"value\": \"1\",\n                \"bestValue\": false\n            },\n            {\n                \"metric\": \"comment_lines\",\n                \"value\": \"22\"\n            },\n            {\n                \"metric\": \"complexity\",\n                \"value\": \"29\"\n            },\n            {\n                \"metric\": \"code_smells\",\n                \"value\": \"1\",\n                \"bestValue\": false\n            }\n        ]\n    }\n}<\/code><\/pre>\n<\/div>\n<p>The <code>component<\/code> refers to the project identifier (e.g., <code>\"Helloworld<\/code>), and the <code>measures<\/code> array contains the actual metrics (e.g., <code>bugs<\/code> and <code>coverage<\/code>) along with their corresponding values.<\/p>\n<h4>2. <strong>Storing Data in GridDB<\/strong><\/h4>\n<p>Once the metrics are fetched from <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a>, they need to be transformed to fit the schema required by <strong>GridDB<\/strong>. <strong>GridDB<\/strong> is a time-series database, and its data model focuses on storing time-stamped records efficiently. Therefore, the <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a> metrics need to be transformed into time-series data that includes the following fields:<\/p>\n<ul>\n<li><strong>Timestamp<\/strong>: The time at which the metric was collected (e.g., <code>2024-11-17T12:00:00Z<\/code>).<\/li>\n<li><strong>Metric Name<\/strong>: The type of metric (e.g., <code>bugs<\/code>, <code>coverage<\/code>).<\/li>\n<li><strong>Metric Value<\/strong>: The value of the metric (e.g., <code>5<\/code>, <code>80.5<\/code>).<\/li>\n<li><strong>Component<\/strong>: The identifier of the project (e.g., <code>project_xyz<\/code>).<\/li>\n<\/ul>\n<p>A typical transformation flow would include:<\/p>\n<ol>\n<li><strong>Parsing the API response<\/strong> into individual metric records.<\/li>\n<li><strong>Creating <code>SonarMetricDTO<\/code> objects<\/strong> to hold the data in the appropriate format, aligning with the <strong>GridDB<\/strong> schema.<\/li>\n<\/ol>\n<div class=\"clipboard\">\n<pre><code class=\"language-java\">package mycode.dto;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport java.util.Date;\n\nimport com.toshiba.mwcloud.gs.RowKey;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\npublic class SonarMetricDTO {\n  @RowKey\n  public Date timestamp; \/\/ Time of the activity\n  private String metricName; \/\/ e.g., coverage, bugs\n  private String metricValue; \/\/ e.g., 80.5, 2\n  private String component; \/\/ Project key (optional, for identification)\n}\nmerged, conflict)\n}<\/code><\/pre>\n<\/div>\n<p>Here, the timestamp is set to the current date and time, and the metric name and value are extracted from the <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a> API response.<\/p>\n<h4><strong>Data Injection<\/strong><\/h4>\n<p>Finally, the transformed data will be loaded into GridDB, where it can be accessed for real-time monitoring and analysis of developer activities. We will insert the data into our database as follows:\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-java\">  TimeSeries<SonarMetricDTO> ts = store.putTimeSeries(\"sonarMetrics\", SonarMetricDTO.class);\n  for (SonarMetricDTO metric : metrics) {\n     ts.append(metric);\n  }Below is the complete `MetricsCollectionService.java`, which implements all the aforementioned steps.<\/code><\/pre>\n<\/div>\n<p><strong>Data Representation in GridDB<\/strong><\/p>\n<p>Once the data is stored, GridDB organizes it into time-series entries. The structure is typically as follows:<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">Timestamp    \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Metric Name    Metric Value     Component\n2024-11-17T12:00:00Z    bugs   \u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a05    \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0project_xyz\n2024-11-17T12:00:00Z    coverage    \u00a0\u00a0\u00a080.5    \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0project_xyz<\/code><\/pre>\n<\/div>\n<p>This enables efficient querying of time-series data, supporting real-time analysis and historical tracking of code quality metrics.<\/p>\n<p>Here is the complete code for <code>MetricsCollectionService<\/code><\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-java\">package mycode.service;\n\nimport java.util.ArrayList;\nimport java.util.Base64;\nimport java.util.Date;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.scheduling.annotation.Scheduled;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.client.RestTemplate;\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson.databind.JsonMappingException;\nimport com.fasterxml.jackson.databind.JsonNode;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.toshiba.mwcloud.gs.*;\nimport mycode.dto.SonarMetricDTO;\nimport java.text.ParseException;\nimport java.util.List;\n\n@Service\npublic class MetricsCollectionService {\n  @Value(\"${sonar.url}\")\n  private String sonarUrl; \/\/ e.g., http:\/\/localhost:9000\n\n  @Value(\"${sonar.token}\")\n  private String sonarToken; \/\/ [SonarQube](https:\/\/www.sonarsource.com\/) authentication token\n\n  @Value(\"${sonar.projectKey}\")\n  private String defaultProjectKey; \/\/ Default project key from properties\n\n  @Value(\"#{'${sonar.metricKeys}'.split(',')}\")\n  private List<String> defaultMetricKeys; \/\/ Default metric keys as a list\n\n  @Autowired\n  GridStore store;\n\n  @Scheduled(fixedRate = 5000)\n  \/**\n   * Fetches metrics from [SonarQube](https:\/\/www.sonarsource.com\/), converts them to DTOs, and saves them.\n   *\/\n  public void collectMetrics() throws GSException, JsonMappingException, JsonProcessingException, ParseException {\n\n    \/\/ Step 1: Authenticate and Fetch Data from [SonarQube](https:\/\/www.sonarsource.com\/)\n    \/\/ Step 1: Authenticate and Fetch Data from [SonarQube](https:\/\/www.sonarsource.com\/)\n    List<SonarMetricDTO> metrics = fetchMetricsFromSonar(defaultProjectKey, defaultMetricKeys);\n\n    \/\/ Step 2: Save the metrics into GridDB\n    TimeSeries<SonarMetricDTO> ts = store.putTimeSeries(\"sonarMetrics\", SonarMetricDTO.class);\n    for (SonarMetricDTO metric : metrics) {\n       ts.append(metric);\n    }\n  }\n\n  private List<SonarMetricDTO> fetchMetricsFromSonar(String projectKey, List<String> metricKeys) {\n    String metricsQuery = String.join(\",\", metricKeys); \/\/ Create CSV of metric keys\n    String apiUrl = sonarUrl + \"\/api\/measures\/component?component=\" + projectKey + \"&metricKeys=\" + metricsQuery;\n\n    RestTemplate restTemplate = new RestTemplate();\n    HttpHeaders headers = new HttpHeaders();\n    headers.set(\"Authorization\", \"Basic \" + Base64.getEncoder().encodeToString((sonarToken + \":\").getBytes()));\n\n    HttpEntity<String> entity = new HttpEntity<>(headers);\n    ResponseEntity<String> response = restTemplate.exchange(apiUrl, HttpMethod.GET, entity, String.class);\n\n    \/\/ Step 1.1: Parse the JSON Response\n    return parseSonarResponse(response.getBody(), projectKey);\n  }\n\n  private List<SonarMetricDTO> parseSonarResponse(String responseBody, String projectKey) {\n    List<SonarMetricDTO> metrics = new ArrayList<>();\n\n    try {\n      \/\/ Parse the JSON response using Jackson\n      ObjectMapper objectMapper = new ObjectMapper();\n      JsonNode rootNode = objectMapper.readTree(responseBody);\n\n      \/\/ Access the \"measures\" array within the response\n      JsonNode measuresNode = rootNode.path(\"component\").path(\"measures\");\n\n      \/\/ Iterate through the \"measures\" array and extract the metrics\n      for (JsonNode measure : measuresNode) {\n        String metricName = measure.path(\"metric\").asText();\n        String value = measure.path(\"value\").asText();\n\n        \/\/ Create and add the metric to the list\n        metrics.add(createMetric(metricName, value, projectKey));\n      }\n    } catch (Exception e) {\n      e.printStackTrace(); \/\/ Handle the exception (e.g., log it)\n    }\n\n    return metrics;\n  }\n\n  \/**\n   * Helper to create a DTO instance.\n   *\/\n  private SonarMetricDTO createMetric(String metricName, String value, String projectKey) {\n    SonarMetricDTO dto = new SonarMetricDTO();\n    dto.setMetricName(metricName);\n    dto.setMetricValue(value + ((int) (Math.random() * 9) + 1));\n    dto.setComponent(projectKey);\n    dto.setTimestamp(new Date()); \/\/ Use current timestamp\n    return dto;\n  }\n\n}<\/code><\/pre>\n<\/div>\n<p>By following above steps, we can effectively extract data from <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a>, load it into GridDB.<\/p>\n<h2><strong>Data Querying in GridDB and Visualization with Thymeleaf<\/strong><\/h2>\n<p>Once the data is stored and available in GridDB, the next step is to visualize this data in a way that provides actionable insights.<\/p>\n<p>In this section, we\u2019ll explore how to build a dashboard using Spring Boot, <code>Thymeleaf<\/code>, and <code>Chart.js<\/code> to render charts that display commits and pull request trends over time.<\/p>\n<p>Here are the steps to achieve this:<\/p>\n<ul>\n<li><strong>Building the Chart Controller<\/strong><\/li>\n<\/ul>\n<p>The <code>ChartController<\/code> acts as the intermediary between backend data in GridDB and the frontend visualizations displayed on the dashboard. Its responsibilities include handling HTTP requests, interacting with the service layer to fetch data, and passing that data to Thymeleaf templates for rendering.<\/p>\n<p>Here\u2019s how the <code>ChartController<\/code> is implemented:<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-java\">package mycode.controller;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.GetMapping;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\n\nimport mycode.service.ChartService;\nimport mycode.dto.SonarMetricDTO;\n\nimport java.text.SimpleDateFormat;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\n@Controller\npublic class ChartController {\n\n  @Autowired\n  ChartService chartService;\n\n  @Autowired\n  private ObjectMapper objectMapper;\n\n  @GetMapping(\"\/charts\")\n  public String showCharts(Model model) {\n    try {\n      List<SonarMetricDTO> events = chartService.getVcsEvents();\n\n      Map<String, Integer> data1 = prepareClassesMetrics(events);\n      Map<String, Integer> data2 = prepareVulnerabilitiesMetrics(events);\n\n      \/\/ Convert Maps to JSON Strings for use in JavaScript in the Thymeleaf template\n      String classesDataJson = objectMapper.writeValueAsString(data1);\n      String vulnerabilityDataJson = objectMapper.writeValueAsString(data2);\n\n      model.addAttribute(\"classesDataJson\", classesDataJson);\n      model.addAttribute(\"vulnerabilityDataJson\", vulnerabilityDataJson);\n\n    } catch (Exception e) {\n      e.printStackTrace();\n    }\n    return \"charts\";\n  }\n\n  private Map<String, Integer> prepareClassesMetrics(List<SonarMetricDTO> events) {\n    Map<String, Integer> commitMap = new HashMap<>();\n    SimpleDateFormat dateFormat = new SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'\");\n\n    for (SonarMetricDTO event : events) {\n      if (\"classes\".equals(event.getMetricName())) {\n        String timestamp = dateFormat.format(event.getTimestamp());\n        commitMap.put(timestamp, Integer.valueOf(event.getComponent()));\n      }\n    }\n    return commitMap;\n  }\n\n  private Map<String, Integer> prepareVulnerabilitiesMetrics(List<SonarMetricDTO> events) {\n    Map<String, Integer> prMap = new HashMap<>();\n    SimpleDateFormat dateFormat = new SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'\");\n\n    for (SonarMetricDTO event : events) {\n      if (\"vulnerabilities\".equals(event.getMetricName())) {\n        String timestamp = dateFormat.format(event.getTimestamp());\n        prMap.put(timestamp, Integer.valueOf(event.getComponent()));\n      }\n    }\n    return prMap;\n  }\n\n}<\/code><\/pre>\n<\/div>\n<ul>\n<li><strong>Implementing the Chart Service<\/strong><\/li>\n<\/ul>\n<p>The <code>ChartService<\/code> acts as the business logic layer, encapsulating the operations needed to query GridDB and process the results.<\/p>\n<p>The <code>ChartService<\/code> class retrieves Sonar code quality metrics from a GridStore database container named &#8220;sonarMetrics&#8221;. The service processes each row of the result, mapping fields like Timestamp, MetricName, MetricValue, and Component into a <code>SonarMetricDTO<\/code> object. Finally, it returns a list of these DTOs representing the Sonar code quality metrics.<\/p>\n<p>Here&#8217;s how the <code>ChartService<\/code> is implemented:<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-java\">package mycode.service;\n\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport com.toshiba.mwcloud.gs.Container;\nimport com.toshiba.mwcloud.gs.GridStore;\nimport com.toshiba.mwcloud.gs.Query;\nimport com.toshiba.mwcloud.gs.Row;\nimport com.toshiba.mwcloud.gs.RowSet;\n\nimport mycode.dto.SonarMetricDTO;\n\n@Service\npublic class ChartService {\n\n  @Autowired\n  GridStore store;\n\n  public List<SonarMetricDTO> getVcsEvents() throws Exception {\n\n    Container<?, Row> container = store.getContainer(\"sonarMetrics\");\n    if (container == null) {\n      throw new Exception(\"Container not found.\");\n    }\n    List<SonarMetricDTO> eventList = new ArrayList<>();\n\n\n    SimpleDateFormat dateFormat = new SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'\");\n    Date now = new Date();\n\n    String nowString = dateFormat.format(now);\n    String startTime = \"1971-12-23T18:18:52.000Z\";\n\n    String queryString = \"select * where Timestamp >= TIMESTAMP('\" + startTime\n        + \"') and Timestamp <= TIMESTAMP('\" + nowString + \"')\";\n    Query<Row> query = container.query(queryString);\n    RowSet<Row> rs = query.fetch();\n\n    while (rs.hasNext()) {\n      Row row = rs.next();\n      SonarMetricDTO event = new SonarMetricDTO();\n      event.setTimestamp(row.getTimestamp(0));\n      event.setMetricName(row.getString(1));\n      event.setMetricValue(row.getString(2));\n      event.setComponent(row.getString(3));\n\n      eventList.add(event); \n\n    }\n    return eventList;\n  }\n\n}<\/code><\/pre>\n<\/div>\n<ul>\n<li><strong>Rendering Charts with Thymeleaf<\/strong><\/li>\n<\/ul>\n<p>With the data fetched and processed, the final step is to render the charts on the dashboard using Thymeleaf templates. Thymeleaf allows you to seamlessly integrate backend data into HTML views, making it a great choice for dynamic, data-driven applications.<\/p>\n<p>Below is the implementation of <code>charts.html<\/code>:<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-html\">&lt;!DOCTYPE html&gt;\n&lt;html xmlns_th=\"http:\/\/www.thymeleaf.org\"&gt;\n\n&lt;head&gt;\n  &lt;title&gt;VCS Activity Charts&lt;\/title&gt;\n  &lt;script src=\"https:\/\/cdn.jsdelivr.net\/npm\/chart.js\"&gt;&lt;\/script&gt;\n  &lt;style&gt;\n    \/* Center the content and add padding *\/\n    body {\n      font-family: Arial, sans-serif;\n      display: flex;\n      justify-content: center;\n      align-items: center;\n      flex-direction: column;\n      margin: 0;\n      padding: 20px;\n      background-color: #f5f5f5;\n    }\n\n    \/* Style containers for each chart *\/\n    .chart-container {\n      background-color: white;\n      border-radius: 8px;\n      box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);\n      padding: 20px;\n      margin: 20px 0;\n      width: 100%;\n      max-width: 600px;\n    }\n\n    \/* Canvas styling with a fixed height *\/\n    canvas {\n      width: 100% !important;\n      height: 300px !important;\n    }\n\n    \/* Chart title styling *\/\n    h2 {\n      text-align: center;\n      color: #333;\n      font-size: 24px;\n      margin-bottom: 20px;\n    }\n  &lt;\/style&gt;\n&lt;\/head&gt;\n\n&lt;body&gt;\n\n  &lt;div class=\"chart-container\"&gt;\n    &lt;h2&gt;Sonar Classes Trend&lt;\/h2&gt;\n    &lt;canvas id=\"commitChart\"&gt;&lt;\/canvas&gt;\n  &lt;\/div&gt;\n\n  &lt;div class=\"chart-container\"&gt;\n    &lt;h2&gt;Sonar Vulnerability Trend\n&lt;\/h2&gt;\n    &lt;canvas id=\"prChart\"&gt;&lt;\/canvas&gt;\n  &lt;\/div&gt;\n\n  &lt;!-- Inline JavaScript block to properly process Thymeleaf variables --&gt;\n  &lt;script th_inline=\"javascript\"&gt;\n    \/\/ Thymeleaf will automatically insert the JSON string correctly\n    const commitData = [[${ classesDataJson }]];\n    const prData = [[${ vulnerabilityDataJson }]];\n\n    \/\/ Parse JSON data into JavaScript objects\n    const parsedCommitData = JSON.parse(commitData);\n    const parsedPrData = JSON.parse(prData);\n\n    \/\/ Helper function to sort the data by date keys\n    function sortByDate(data) {\n      return Object.keys(data)\n        .sort((a, b) =&gt; new Date(a) - new Date(b))  \/\/ Sort the date strings in ascending order\n        .reduce((obj, key) =&gt; {\n          obj[key] = data[key]; \/\/ Rebuild the object in sorted order\n          return obj;\n        }, {});\n    }\n\n    \/\/ Sort the commit and PR data by date\n    const sortedCommitData = sortByDate(parsedCommitData);\n    const sortedPrData = sortByDate(parsedPrData);\n\n    \/\/ Extract labels (dates) and values (counts) for Commit chart\n    const commitLabels = Object.keys(sortedCommitData);\n    const commitValues = Object.values(sortedCommitData);\n\n    \/\/ Extract labels (dates) and values (counts) for Pull Request chart\n    const prLabels = Object.keys(sortedPrData);\n    const prValues = Object.values(sortedPrData);\n\n    \/\/ Commit Activity Chart\n    const commitCtx = document.getElementById('commitChart').getContext('2d');\n    const commitChart = new Chart(commitCtx, {\n      type: 'line',\n      data: {\n        labels: commitLabels,\n        datasets: [{\n          label: 'Classes Coverage',\n          data: commitValues,\n          backgroundColor: 'rgba(75, 192, 192, 0.2)',\n          borderColor: 'rgba(75, 192, 192, 1)',\n          borderWidth: 2\n        }]\n      },\n      options: {\n        responsive: true,\n        maintainAspectRatio: true,\n        scales: {\n          y: {\n            beginAtZero: true\n          }\n        }\n      }\n    });\n\n    \/\/ Pull Request Activity Chart\n    const prCtx = document.getElementById('prChart').getContext('2d');\n    const prChart = new Chart(prCtx, {\n      type: 'line',\n      data: {\n        labels: prLabels,\n        datasets: [{\n          label: ' Vulnerabilities Count',\n          data: prValues,\n          backgroundColor: 'rgba(153, 102, 255, 0.2)',\n          borderColor: 'rgba(153, 102, 255, 1)',\n          borderWidth: 2\n        }]\n      },\n      options: {\n        responsive: true,\n        maintainAspectRatio: true,\n        scales: {\n          y: {\n            beginAtZero: true\n          }\n        }\n      }\n    });\n  &lt;\/script&gt;\n\n\n&lt;\/body&gt;\n\n&lt;\/html&gt;<\/code><\/pre>\n<\/div>\n<h3>Running the Project<\/h3>\n<p>To run the project, execute the following command to build and run our application:<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">mvn clean install && mvn spring-boot:run \u00a0<\/code><\/pre>\n<\/div>\n<h3>Accessing the Dashboard<\/h3>\n<p>Once the application is up and running, open a web browser and navigate to <code>http:\/\/localhost:9090<\/code>. This URL will display our Thymeleaf-based dashboard, where we can view charts visualizing commit activity and pull request activity over time.<\/p>\n<p><img decoding=\"async\" title=\"\" src=\".\/img\/chart.png\" alt=\"\" width=\"752\"><\/p>\n<p>The charts on this dashboard is dynamically rendered using data retrieved from Github and processed by the application\u2019s <code>ChartService<\/code>.<\/p>\n<p><strong>Data Storage in GridDB:<\/strong><\/p>\n<p>The GridDB Shell tool allows for  access and querying of data via the command line, as illustrated below.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">gs[public]> select * from sonarMetrics;\ngs[public]> get 39<\/code><\/pre>\n<\/div>\n<h3><strong>Conclusion:<\/strong><\/h3>\n<p>Integrating <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a> with GridDB for metrics collection provides a powerful mechanism to monitor, analyze, and improve code quality over time. By leveraging <a href=\"https:\/\/www.sonarsource.com\/\">SonarQube<\/a>&#8216;s REST API, organizations can extract critical metrics such as bugs, code smells, and test coverage. Storing these metrics in GridDB&#8217;s high-performance time-series database ensures efficient historical tracking and supports real-time analysis.<\/p>\n<p>This streamlined approach empowers development teams to:<\/p>\n<ul>\n<li><strong>Detect Trends<\/strong>: Identify patterns of improvement or regression in code quality.<\/li>\n<li><strong>Enhance Decision-Making<\/strong>: Base development priorities on quantitative metrics.<\/li>\n<li><strong>Ensure Long-Term Sustainability<\/strong>: Continuously monitor and optimize codebases.<\/li>\n<\/ul>\n<p>By automating metric collection and storage, teams can focus on addressing root causes of technical debt and improving overall software health. This integration is not just a monitoring tool but can be a strategic investment in building maintainable, secure, and high-quality software systems.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction SonarQube is widely used for continuous code quality inspection, helping teams detect bugs and vulnerabilities early. However, as projects scale, the backend database can become a bottleneck, affecting performance. Integrating GridDB, a high-performance, distributed NoSQL database, with SonarQube enhances its data processing capabilities, providing faster insights and better scalability for large projects. This blog [&hellip;]<\/p>\n","protected":false},"author":41,"featured_media":51985,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[121],"tags":[],"class_list":["post-52139","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Griddb SonarQube Integration | GridDB: Open Source Time Series Database for IoT<\/title>\n<meta name=\"description\" content=\"Introduction SonarQube is widely used for continuous code quality inspection, helping teams detect bugs and vulnerabilities early. However, as projects\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Griddb SonarQube Integration | GridDB: Open Source Time Series Database for IoT\" \/>\n<meta property=\"og:description\" content=\"Introduction SonarQube is widely used for continuous code quality inspection, helping teams detect bugs and vulnerabilities early. However, as projects\" \/>\n<meta property=\"og:url\" content=\"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/\" \/>\n<meta property=\"og:site_name\" content=\"GridDB: Open Source Time Series Database for IoT\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/griddbcommunity\/\" \/>\n<meta property=\"article:published_time\" content=\"2025-06-05T07:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/12\/blog_title_21.png\" \/>\n\t<meta property=\"og:image:width\" content=\"870\" \/>\n\t<meta property=\"og:image:height\" content=\"490\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"griddb-admin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@GridDBCommunity\" \/>\n<meta name=\"twitter:site\" content=\"@GridDBCommunity\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"griddb-admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"15 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/\"},\"author\":{\"name\":\"griddb-admin\",\"@id\":\"https:\/\/griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233\"},\"headline\":\"Griddb SonarQube Integration\",\"datePublished\":\"2025-06-05T07:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/\"},\"wordCount\":1682,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/griddb.net\/en\/#organization\"},\"image\":{\"@id\":\"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/#primaryimage\"},\"thumbnailUrl\":\"\/wp-content\/uploads\/2025\/12\/blog_title_21.png\",\"articleSection\":[\"Blog\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/\",\"url\":\"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/\",\"name\":\"Griddb SonarQube Integration | GridDB: Open Source Time Series Database for IoT\",\"isPartOf\":{\"@id\":\"https:\/\/griddb.net\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/#primaryimage\"},\"thumbnailUrl\":\"\/wp-content\/uploads\/2025\/12\/blog_title_21.png\",\"datePublished\":\"2025-06-05T07:00:00+00:00\",\"description\":\"Introduction SonarQube is widely used for continuous code quality inspection, helping teams detect bugs and vulnerabilities early. However, as projects\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/#primaryimage\",\"url\":\"\/wp-content\/uploads\/2025\/12\/blog_title_21.png\",\"contentUrl\":\"\/wp-content\/uploads\/2025\/12\/blog_title_21.png\",\"width\":870,\"height\":490},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/griddb.net\/en\/#website\",\"url\":\"https:\/\/griddb.net\/en\/\",\"name\":\"GridDB: Open Source Time Series Database for IoT\",\"description\":\"GridDB is an open source time-series database with the performance of NoSQL and convenience of SQL\",\"publisher\":{\"@id\":\"https:\/\/griddb.net\/en\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/griddb.net\/en\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/griddb.net\/en\/#organization\",\"name\":\"Fixstars\",\"url\":\"https:\/\/griddb.net\/en\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/griddb.net\/en\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png\",\"contentUrl\":\"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png\",\"width\":200,\"height\":83,\"caption\":\"Fixstars\"},\"image\":{\"@id\":\"https:\/\/griddb.net\/en\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/griddbcommunity\/\",\"https:\/\/x.com\/GridDBCommunity\",\"https:\/\/www.linkedin.com\/company\/griddb-by-toshiba\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233\",\"name\":\"griddb-admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/griddb.net\/en\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g\",\"caption\":\"griddb-admin\"},\"url\":\"https:\/\/griddb.net\/en\/author\/griddb-admin\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Griddb SonarQube Integration | GridDB: Open Source Time Series Database for IoT","description":"Introduction SonarQube is widely used for continuous code quality inspection, helping teams detect bugs and vulnerabilities early. However, as projects","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/","og_locale":"en_US","og_type":"article","og_title":"Griddb SonarQube Integration | GridDB: Open Source Time Series Database for IoT","og_description":"Introduction SonarQube is widely used for continuous code quality inspection, helping teams detect bugs and vulnerabilities early. However, as projects","og_url":"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/","og_site_name":"GridDB: Open Source Time Series Database for IoT","article_publisher":"https:\/\/www.facebook.com\/griddbcommunity\/","article_published_time":"2025-06-05T07:00:00+00:00","og_image":[{"width":870,"height":490,"url":"https:\/\/griddb.net\/wp-content\/uploads\/2025\/12\/blog_title_21.png","type":"image\/png"}],"author":"griddb-admin","twitter_card":"summary_large_image","twitter_creator":"@GridDBCommunity","twitter_site":"@GridDBCommunity","twitter_misc":{"Written by":"griddb-admin","Est. reading time":"15 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/#article","isPartOf":{"@id":"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/"},"author":{"name":"griddb-admin","@id":"https:\/\/griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233"},"headline":"Griddb SonarQube Integration","datePublished":"2025-06-05T07:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/"},"wordCount":1682,"commentCount":0,"publisher":{"@id":"https:\/\/griddb.net\/en\/#organization"},"image":{"@id":"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/#primaryimage"},"thumbnailUrl":"\/wp-content\/uploads\/2025\/12\/blog_title_21.png","articleSection":["Blog"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/","url":"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/","name":"Griddb SonarQube Integration | GridDB: Open Source Time Series Database for IoT","isPartOf":{"@id":"https:\/\/griddb.net\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/#primaryimage"},"image":{"@id":"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/#primaryimage"},"thumbnailUrl":"\/wp-content\/uploads\/2025\/12\/blog_title_21.png","datePublished":"2025-06-05T07:00:00+00:00","description":"Introduction SonarQube is widely used for continuous code quality inspection, helping teams detect bugs and vulnerabilities early. However, as projects","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/griddb.net\/en\/blog\/griddb-sonarqube-integration\/#primaryimage","url":"\/wp-content\/uploads\/2025\/12\/blog_title_21.png","contentUrl":"\/wp-content\/uploads\/2025\/12\/blog_title_21.png","width":870,"height":490},{"@type":"WebSite","@id":"https:\/\/griddb.net\/en\/#website","url":"https:\/\/griddb.net\/en\/","name":"GridDB: Open Source Time Series Database for IoT","description":"GridDB is an open source time-series database with the performance of NoSQL and convenience of SQL","publisher":{"@id":"https:\/\/griddb.net\/en\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/griddb.net\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/griddb.net\/en\/#organization","name":"Fixstars","url":"https:\/\/griddb.net\/en\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/griddb.net\/en\/#\/schema\/logo\/image\/","url":"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png","contentUrl":"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png","width":200,"height":83,"caption":"Fixstars"},"image":{"@id":"https:\/\/griddb.net\/en\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/griddbcommunity\/","https:\/\/x.com\/GridDBCommunity","https:\/\/www.linkedin.com\/company\/griddb-by-toshiba"]},{"@type":"Person","@id":"https:\/\/griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233","name":"griddb-admin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/griddb.net\/en\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g","caption":"griddb-admin"},"url":"https:\/\/griddb.net\/en\/author\/griddb-admin\/"}]}},"_links":{"self":[{"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/posts\/52139","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/comments?post=52139"}],"version-history":[{"count":0,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/posts\/52139\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/media\/51985"}],"wp:attachment":[{"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/media?parent=52139"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/categories?post=52139"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/tags?post=52139"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}