--- /dev/null
+<form>
+ <div class="modal-head">
+ {{#if change}}
+ <h2>{{t 'coding_rules.update_custom_rule'}}</h2>
+ {{else}}
+ <h2>{{t 'coding_rules.create_custom_rule'}}</h2>
+ {{/if}}
+ </div>
+
+ <div class="modal-body">
+ <div class="modal-error"></div>
+ <div class="modal-warning">{{t 'coding_rules.reactivate.help'}}</div>
+
+ <table>
+ <tr class="property">
+ <th><h3>{{t 'name'}} <em class="mandatory">*</em></h3></th>
+ <td>
+ <input type="text" name="name" id="coding-rules-custom-rule-creation-name"
+ class="coding-rules-name-key" value="{{name}}"/>
+ </td>
+ </tr>
+ <tr class="property">
+ <th><h3>{{t 'key'}}{{#unless change}} <em class="mandatory">*</em>{{/unless}}</h3></th>
+ <td>
+ {{#if change}}
+ <span class="coding-rules-detail-custom-rule-key" title="{{key}}">{{key}}</span>
+ {{else}}
+ <input type="text" name="key" id="coding-rules-custom-rule-creation-key"
+ class="coding-rules-name-key" value="{{internalKey}}"/>
+ {{/if}}
+ </td>
+ </tr>
+ <tr class="property">
+ <th><h3>{{t 'description'}} <em class="mandatory">*</em></h3></th>
+ <td>
+ <textarea name="markdown_description" id="coding-rules-custom-rule-creation-html-description"
+ class="coding-rules-markdown-description" rows="15">{{{mdDesc}}}</textarea>
+ <span class="right">{{> '_markdown-tips' }}</span>
+ </td>
+ </tr>
+ <tr class="property">
+ <th><h3>{{t 'severity'}}</h3></th>
+ <td>
+ <select id="coding-rules-custom-rule-creation-severity">
+ {{#each severities}}
+ <option value="{{this}}">{{t 'severity' this}}</option>
+ {{/each}}
+ </select>
+ </td>
+ </tr>
+ <tr class="property">
+ <th><h3>{{t 'coding_rules.filters.status'}}</h3></th>
+ <td>
+ <select id="coding-rules-custom-rule-creation-status">
+ {{#each statuses}}
+ <option value="{{id}}">{{text}}</option>
+ {{/each}}
+ </select>
+ </td>
+ </tr>
+ {{#each params}}
+ <tr class="property">
+ <th><h3>{{key}}</h3></th>
+ <td>
+ {{#eq type 'TEXT'}}
+ <textarea class="width100" rows="3" name="{{key}}" placeholder="{{defaultValue}}">{{value}}</textarea>
+ {{else}}
+ <input type="text" name="{{key}}" value="{{value}}" placeholder="{{defaultValue}}"/>
+ {{/eq}}
+ <div class="note">{{htmlDesc}}</div>
+ {{#if extra}}
+ <div class="note">{{extra}}</div>
+ {{/if}}
+ </td>
+ </tr>
+ {{/each}}
+ </table>
+ </div>
+
+ <div class="modal-foot">
+ <button id="coding-rules-custom-rule-creation-create">
+ {{#if change}}{{t 'save'}}{{else}}{{t 'create'}}{{/if}}
+ </button>
+ <a id="coding-rules-custom-rule-creation-cancel" class="action">{{t 'cancel'}}</a>
+ </div>
+</form>
</td>
<td class="coding-rules-detail-list-parameters">
- {{#each parameters}}
- <div class="coding-rules-detail-list-parameter">
- <span class="key">{{key}}</span><span class="sep">: </span><span class="value" title="{{value}}">{{value}}</span>
- </div>
+ {{#each params}}
+ {{#if defaultValue}}
+ <div class="coding-rules-detail-list-parameter">
+ <span class="key">{{key}}</span><span class="sep">: </span><span class="value" title="{{value}}">{{defaultValue}}</span>
+ </div>
+ {{/if}}
{{/each}}
</td>
{{#if canWrite}}
<div class="button-group coding-rules-detail-quality-profiles-activation">
- <button id="coding-rules-custom-rules-create">{{t 'coding_rules.create'}}</button>
+ <button class="js-create-custom-rule">{{t 'coding_rules.create'}}</button>
</div>
{{/if}}
<table id="coding-rules-detail-custom-rules" class="coding-rules-detail-list"></table>
define([
'components/navigator/controller',
+ 'coding-rules/models/rule',
'coding-rules/rule-details-view'
-], function (Controller, RuleDetailsView) {
+], function (Controller, Rule, RuleDetailsView) {
var $ = jQuery;
showDetails: function (rule) {
var that = this,
- ruleModel = typeof rule === 'string' ? new Backbone.Model({ key: rule }) : rule;
+ ruleModel = typeof rule === 'string' ? new Rule({ key: rule }) : rule;
this.app.layout.workspaceDetailsRegion.reset();
this.getRuleDetails(ruleModel).done(function (data) {
key.setScope('details');
--- /dev/null
+define([
+ 'common/modals',
+ 'templates/coding-rules'
+], function (Modal, Templates) {
+
+ var $ = jQuery;
+
+ return Modal.extend({
+ template: Templates['coding-rules-custom-rule-creation'],
+
+ ui: {
+ customRuleCreationKey: '#coding-rules-custom-rule-creation-key',
+ customRuleCreationName: '#coding-rules-custom-rule-creation-name',
+ customRuleCreationHtmlDescription: '#coding-rules-custom-rule-creation-html-description',
+ customRuleCreationSeverity: '#coding-rules-custom-rule-creation-severity',
+ customRuleCreationStatus: '#coding-rules-custom-rule-creation-status',
+ customRuleCreationParameters: '[name]',
+ customRuleCreationCreate: '#coding-rules-custom-rule-creation-create',
+ customRuleCreationReactivate: '#coding-rules-custom-rule-creation-reactivate',
+ modalFoot: '.modal-foot'
+ },
+
+ events: function () {
+ return _.extend(Modal.prototype.events.apply(this, arguments), {
+ 'input @ui.customRuleCreationName': 'generateKey',
+ 'keydown @ui.customRuleCreationName': 'generateKey',
+ 'keyup @ui.customRuleCreationName': 'generateKey',
+
+ 'input @ui.customRuleCreationKey': 'flagKey',
+ 'keydown @ui.customRuleCreationKey': 'flagKey',
+ 'keyup @ui.customRuleCreationKey': 'flagKey',
+
+ 'click #coding-rules-custom-rule-creation-cancel': 'close',
+ 'click @ui.customRuleCreationCreate': 'create',
+ 'click @ui.customRuleCreationReactivate': 'reactivate'
+ });
+ },
+
+ generateKey: function () {
+ if (!this.keyModifiedByUser) {
+ if (this.ui.customRuleCreationKey) {
+ var generatedKey = this.ui.customRuleCreationName.val().latinize().replace(/[^A-Za-z0-9]/g, '_');
+ this.ui.customRuleCreationKey.val(generatedKey);
+ }
+ }
+ },
+
+ flagKey: function () {
+ this.keyModifiedByUser = true;
+ // Cannot use @ui.customRuleCreationReactivate.hide() directly since it was not there at initial render
+ jQuery(this.ui.customRuleCreationReactivate.selector).hide();
+ },
+
+ onRender: function () {
+ Modal.prototype.onRender.apply(this, arguments);
+
+ this.keyModifiedByUser = false;
+
+ var format = function (state) {
+ if (!state.id) {
+ return state.text;
+ } else {
+ return '<i class="icon-severity-' + state.id.toLowerCase() + '"></i> ' + state.text;
+ }
+ },
+ severity = (this.model && this.model.get('severity')) || this.options.templateRule.get('severity'),
+ status = (this.model && this.model.get('status')) || this.options.templateRule.get('status');
+
+ this.ui.customRuleCreationSeverity.val(severity);
+ this.ui.customRuleCreationSeverity.select2({
+ width: '250px',
+ minimumResultsForSearch: 999,
+ formatResult: format,
+ formatSelection: format
+ });
+
+ this.ui.customRuleCreationStatus.val(status);
+ this.ui.customRuleCreationStatus.select2({
+ width: '250px',
+ minimumResultsForSearch: 999
+ });
+ },
+
+ create: function (e) {
+ e.preventDefault();
+ var action = (this.model && this.model.has('key')) ? 'update' : 'create',
+ options = {
+ name: this.ui.customRuleCreationName.val(),
+ markdown_description: this.ui.customRuleCreationHtmlDescription.val(),
+ severity: this.ui.customRuleCreationSeverity.val(),
+ status: this.ui.customRuleCreationStatus.val()
+ };
+ if (this.model && this.model.has('key')) {
+ options.key = this.model.get('key');
+ } else {
+ _.extend(options, {
+ template_key: this.options.templateRule.get('key'),
+ custom_key: this.ui.customRuleCreationKey.val(),
+ prevent_reactivation: true
+ });
+ }
+ var params = this.ui.customRuleCreationParameters.map(function () {
+ var node = $(this),
+ value = node.val();
+ if (!value && action === 'create') {
+ value = node.prop('placeholder') || '';
+ }
+ return {
+ key: node.prop('name'),
+ value: value
+ };
+ }).get();
+ options.params = params.map(function (param) {
+ return param.key + '=' + window.csvEscape(param.value);
+ }).join(';');
+ this.sendRequest(action, options);
+ },
+
+ reactivate: function () {
+ var options = {
+ name: this.existingRule.name,
+ markdown_description: this.existingRule.mdDesc,
+ severity: this.existingRule.severity,
+ status: this.existingRule.status,
+ template_key: this.existingRule.templateKey,
+ custom_key: this.ui.customRuleCreationKey.val(),
+ prevent_reactivation: false
+ },
+ params = this.existingRule.params;
+ options.params = params.map(function (param) {
+ return param.key + '=' + param.defaultValue;
+ }).join(';');
+ this.sendRequest('create', options);
+ },
+
+ sendRequest: function (action, options) {
+ this.$('.modal-error').hide();
+ this.$('.modal-warning').hide();
+ var that = this,
+ origFooter = this.ui.modalFoot.html(),
+ url = baseUrl + '/api/rules/' + action;
+ return $.post(url, options).done(function () {
+ that.options.app.controller.showDetails(that.options.templateRule);
+ that.close();
+ }).fail(function (jqXHR, textStatus, errorThrown) {
+ if (jqXHR.status === 409) {
+ that.existingRule = jqXHR.responseJSON.rule;
+ that.$('.modal-warning').show();
+ that.ui.modalFoot.html(Templates['coding-rules-custom-rule-reactivation']());
+ } else {
+ jQuery.ajaxSettings.error(jqXHR, textStatus, errorThrown);
+ that.ui.modalFoot.html(origFooter);
+ }
+ });
+ },
+
+ serializeData: function () {
+ var params = {};
+ if (this.options.templateRule) {
+ params = this.options.templateRule.get('params');
+ } else if (this.model && this.model.has('params')) {
+ params = this.model.get('params').map(function (p) {
+ _.extend(p, { value: p.defaultValue });
+ });
+ }
+
+ var statuses = ['READY', 'BETA', 'DEPRECATED'].map(function (status) {
+ return {
+ id: status,
+ text: t('rules.status', status.toLowerCase())
+ };
+ });
+
+ return _.extend(Modal.prototype.serializeData.apply(this, arguments), {
+ change: this.model && this.model.has('key'),
+ params: params,
+ severities: ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO'],
+ statuses: statuses
+ });
+ }
+ });
+
+});
define([
'backbone.marionette',
'templates/coding-rules',
- 'coding-rules/rule/custom-rule-view'
-], function (Marionette, Templates, CustomRuleView) {
+ 'coding-rules/rule/custom-rule-view',
+ 'coding-rules/rule/custom-rule-creation-view'
+], function (Marionette, Templates, CustomRuleView, CustomRuleCreationView) {
return Marionette.CompositeView.extend({
template: Templates['coding-rules-custom-rules'],
'change': 'render'
},
+ events: {
+ 'click .js-create-custom-rule': 'createCustomRule'
+ },
+
onRender: function () {
this.$el.toggleClass('hidden', !this.model.get('isTemplate'));
},
+ createCustomRule: function () {
+ new CustomRuleCreationView({
+ app: this.options.app,
+ templateRule: this.model
+ }).render();
+ },
+
serializeData: function () {
return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), {
canWrite: this.options.app.canWrite
--- /dev/null
+/* global casper:false */
+
+var lib = require('../lib');
+
+lib.initMessages();
+lib.changeWorkingDirectory('coding-rules-page-should-create-custom-rules');
+
+
+casper.test.begin('coding-rules-page-should-delete-create-rules', 2, function (test) {
+ casper
+ .start(lib.buildUrl('coding-rules'), function () {
+ lib.setDefaultViewport();
+
+ lib.mockRequest('/api/l10n/index', '{}');
+ lib.mockRequestFromFile('/api/rules/app', 'app.json');
+ this.customRulesSearchMock = lib.mockRequestFromFile('/api/rules/search', 'search-custom-rules.json',
+ { data: { template_key: 'squid:ArchitecturalConstraint' } });
+ this.searchMock = lib.mockRequestFromFile('/api/rules/search', 'search.json');
+ lib.mockRequestFromFile('/api/rules/show', 'show.json');
+ lib.mockRequest('/api/rules/create', '{}');
+ })
+
+ .then(function () {
+ casper.waitForSelector('.coding-rule.selected', function () {
+ casper.click('.coding-rule.selected .js-rule');
+ });
+ })
+
+ .then(function () {
+ casper.waitForSelector('#coding-rules-detail-custom-rules .coding-rules-detail-list-name');
+ })
+
+ .then(function () {
+ lib.clearRequestMock(this.customRulesSearchMock);
+ lib.clearRequestMock(this.searchMock);
+ lib.mockRequestFromFile('/api/rules/search', 'search-custom-rules2.json');
+ })
+
+ .then(function () {
+ test.assertElementCount('#coding-rules-detail-custom-rules .coding-rules-detail-list-name', 1);
+ casper.click('.js-create-custom-rule');
+ casper.fillForm('.modal form', {
+ name: 'test',
+ markdown_description: 'test'
+ });
+ casper.click('#coding-rules-custom-rule-creation-create');
+ lib.waitForElementCount('#coding-rules-detail-custom-rules .coding-rules-detail-list-name', 2, function () {
+ test.assert(true); // put dummy assert into wait statement
+ });
+ })
+
+ .run(function () {
+ test.done();
+ });
+});
--- /dev/null
+{
+ "canWrite": true,
+ "qualityprofiles": [
+ {
+ "key": "java-default-with-mojo-conventions-49307",
+ "name": "Default - Maven Conventions",
+ "lang": "java",
+ "parentKey": "java-top-profile-without-formatting-conventions-50037"
+ },
+ {
+ "key": "java-default-with-sonarsource-conventions-27339",
+ "name": "Default - SonarSource conventions",
+ "lang": "java",
+ "parentKey": "java-top-profile-without-formatting-conventions-50037"
+ },
+ {
+ "key": "java-top-profile-without-formatting-conventions-50037",
+ "name": "Default - Top",
+ "lang": "java"
+ },
+ {
+ "key": "java-findbugs-14954",
+ "name": "FindBugs",
+ "lang": "java"
+ },
+ {
+ "key": "java-for-sq-java-plugin-only-92289",
+ "name": "For SQ Java Plugin Only",
+ "lang": "java",
+ "parentKey": "java-default-with-sonarsource-conventions-27339"
+ },
+ {
+ "key": "java-for-sq-only-95381",
+ "name": "For SQ Only",
+ "lang": "java",
+ "parentKey": "java-default-with-sonarsource-conventions-27339"
+ },
+ {
+ "key": "php-psr-2-06315",
+ "name": "PSR-2",
+ "lang": "php"
+ },
+ {
+ "key": "java-sonar-way-80423",
+ "name": "Sonar way",
+ "lang": "java"
+ },
+ {
+ "key": "js-sonar-way",
+ "name": "Sonar way",
+ "lang": "js"
+ },
+ {
+ "key": "php-sonar-way-05548",
+ "name": "Sonar way",
+ "lang": "php"
+ },
+ {
+ "key": "py-sonar-way-80265",
+ "name": "Sonar way",
+ "lang": "py"
+ },
+ {
+ "key": "java-without-findbugs",
+ "name": "Without Findbugs",
+ "lang": "java"
+ }
+ ],
+ "languages": {
+ "py": "Python",
+ "js": "JavaScript",
+ "php": "PHP",
+ "java": "Java"
+ },
+ "repositories": [
+ {
+ "key": "common-java",
+ "name": "Common SonarQube",
+ "language": "java"
+ },
+ {
+ "key": "common-js",
+ "name": "Common SonarQube",
+ "language": "js"
+ },
+ {
+ "key": "common-php",
+ "name": "Common SonarQube",
+ "language": "php"
+ },
+ {
+ "key": "common-py",
+ "name": "Common SonarQube",
+ "language": "py"
+ },
+ {
+ "key": "Pylint",
+ "name": "Pylint",
+ "language": "py"
+ },
+ {
+ "key": "javascript",
+ "name": "SonarQube",
+ "language": "js"
+ },
+ {
+ "key": "php",
+ "name": "SonarQube",
+ "language": "php"
+ },
+ {
+ "key": "python",
+ "name": "SonarQube",
+ "language": "py"
+ },
+ {
+ "key": "squid",
+ "name": "SonarQube",
+ "language": "java"
+ }
+ ],
+ "statuses": {
+ "BETA": "Beta",
+ "DEPRECATED": "Deprecated",
+ "READY": "Ready"
+ },
+ "characteristics": {
+ "UNDERSTANDABILITY": "Maintainability: Understandability",
+ "MAINTAINABILITY": "Maintainability",
+ "TIME_ZONE_RELATED_PORTABILITY": "Portability: Time zone related portability",
+ "READABILITY": "Maintainability: Readability",
+ "SECURITY_FEATURES": "Security: Security features",
+ "ARCHITECTURE_RELIABILITY": "Reliability: Architecture related reliability",
+ "OS_RELATED_PORTABILITY": "Portability: OS related portability",
+ "EXCEPTION_HANDLING": "Reliability: Exception handling",
+ "LOGIC_CHANGEABILITY": "Changeability: Logic related changeability",
+ "SOFTWARE_RELATED_PORTABILITY": "Portability: Software related portability",
+ "INPUT_VALIDATION_AND_REPRESENTATION": "Security: Input validation and representation",
+ "LANGUAGE_RELATED_PORTABILITY": "Portability: Language related portability",
+ "ERRORS": "Security: Errors",
+ "SECURITY": "Security",
+ "RELIABILITY": "Reliability",
+ "PORTABILITY": "Portability",
+ "HARDWARE_RELATED_PORTABILITY": "Portability: Hardware related portability",
+ "SYNCHRONIZATION_RELIABILITY": "Reliability: Synchronization related reliability",
+ "TRANSPORTABILITY": "Reusability: Transportability",
+ "COMPILER_RELATED_PORTABILITY": "Portability: Compiler related portability",
+ "RESOURCE_RELIABILITY": "Reliability: Resource",
+ "CPU_EFFICIENCY": "Efficiency: Processor use",
+ "EFFICIENCY": "Efficiency",
+ "CHANGEABILITY": "Changeability",
+ "DATA_CHANGEABILITY": "Changeability: Data related changeability",
+ "API_ABUSE": "Security: API abuse",
+ "ARCHITECTURE_CHANGEABILITY": "Changeability: Architecture related changeability",
+ "UNIT_TESTS": "Reliability: Unit tests",
+ "INSTRUCTION_RELIABILITY": "Reliability: Instruction related reliability",
+ "REUSABILITY": "Reusability",
+ "MODULARITY": "Reusability: Modularity",
+ "UNIT_TESTABILITY": "Testability: Unit level testability",
+ "TESTABILITY": "Testability",
+ "INTEGRATION_TESTABILITY": "Testability: Integration level testability",
+ "NETWORK_USE": "Efficiency: Network use",
+ "MEMORY_EFFICIENCY": "Efficiency: Memory use",
+ "DATA_RELIABILITY": "Reliability: Data related reliability",
+ "FAULT_TOLERANCE": "Reliability: Fault tolerance",
+ "LOGIC_RELIABILITY": "Reliability: Logic related reliability"
+ }
+}
--- /dev/null
+{
+ "total": 1,
+ "p": 1,
+ "ps": 10,
+ "rules": [
+ {
+ "key": "squid:Do_not_use_org_h2_util_StringUtils",
+ "name": "Do not use org.h2.util.StringUtils",
+ "severity": "MAJOR",
+ "params": [
+ {
+ "key": "fromClasses",
+ "htmlDesc": "Optional. If this property is not defined, all classes should adhere to this constraint. Ex : *<em>.web.</em>*",
+ "type": "STRING",
+ "defaultValue": ""
+ },
+ {
+ "key": "toClasses",
+ "htmlDesc": "Mandatory. Ex : java.util.Vector, java.util.Hashtable, java.util.Enumeration",
+ "type": "STRING",
+ "defaultValue": "org.h2.util.StringUtils"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "total": 2,
+ "p": 1,
+ "ps": 10,
+ "rules": [
+ {
+ "key": "squid:Do_not_use_org_h2_util_StringUtils",
+ "name": "Do not use org.h2.util.StringUtils",
+ "severity": "MAJOR",
+ "params": [
+ {
+ "key": "fromClasses",
+ "htmlDesc": "Optional. If this property is not defined, all classes should adhere to this constraint. Ex : *<em>.web.</em>*",
+ "type": "STRING",
+ "defaultValue": ""
+ },
+ {
+ "key": "toClasses",
+ "htmlDesc": "Mandatory. Ex : java.util.Vector, java.util.Hashtable, java.util.Enumeration",
+ "type": "STRING",
+ "defaultValue": "org.h2.util.StringUtils"
+ }
+ ]
+ },
+ {
+ "key": "squid:Do_not_use_edu_emory_mathcs_backport_java_util_Collections",
+ "name": "Do not use edu.emory.mathcs.backport.java.util.Collections",
+ "severity": "MAJOR",
+ "params": [
+ {
+ "key": "fromClasses",
+ "htmlDesc": "Optional. If this property is not defined, all classes should adhere to this constraint. Ex : *<em>.web.</em>*",
+ "type": "STRING",
+ "defaultValue": ""
+ },
+ {
+ "key": "toClasses",
+ "htmlDesc": "Mandatory. Ex : java.util.Vector, java.util.Hashtable, java.util.Enumeration",
+ "type": "STRING",
+ "defaultValue": "edu.emory.mathcs.backport.java.util.Collections"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "total": 1,
+ "p": 1,
+ "ps": 200,
+ "rules": [
+ {
+ "key": "squid:ArchitecturalConstraint",
+ "name": "Architectural constraint",
+ "lang": "java",
+ "langName": "Java",
+ "sysTags": [],
+ "tags": [],
+ "status": "READY"
+ }
+ ],
+ "facets": [
+ {
+ "property": "languages",
+ "values": [
+ {
+ "val": "java",
+ "count": 1
+ }
+ ]
+ },
+ {
+ "property": "repositories",
+ "values": [
+ {
+ "val": "squid",
+ "count": 1
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "rule": {
+ "key": "squid:ArchitecturalConstraint",
+ "repo": "squid",
+ "name": "Architectural constraint",
+ "createdAt": "2013-03-27T09:52:40+0100",
+ "severity": "MAJOR",
+ "status": "READY",
+ "internalKey": "ArchitecturalConstraint",
+ "isTemplate": true,
+ "tags": [],
+ "sysTags": [],
+ "lang": "java",
+ "langName": "Java",
+ "htmlDesc": "<p>A source code comply to an architectural model when it fully\n\tadheres to a set of architectural constraints. A constraint allows to\n\tdeny references between classes by pattern.</p>\n<p>You can for instance use this rule to :</p>\n<ul>\n\t<li>forbid access to **.web.** from **.dao.** classes</li>\n\t<li>forbid access to java.util.Vector, java.util.Hashtable and\n\t\tjava.util.Enumeration from any classes</li>\n\t<li>forbid access to java.sql.** from **.ui.** and **.web.**\n\t\tclasses</li>\n</ul>",
+ "debtChar": "CHANGEABILITY",
+ "debtSubChar": "ARCHITECTURE_CHANGEABILITY",
+ "debtCharName": "Changeability",
+ "debtSubCharName": "Architecture related changeability",
+ "debtOverloaded": true,
+ "debtRemFnType": "LINEAR",
+ "debtRemFnCoeff": "3h",
+ "params": [
+ {
+ "key": "fromClasses",
+ "htmlDesc": "Optional. If this property is not defined, all classes should adhere to this constraint. Ex : *<em>.web.</em>*",
+ "type": "STRING"
+ },
+ {
+ "key": "toClasses",
+ "htmlDesc": "Mandatory. Ex : java.util.Vector, java.util.Hashtable, java.util.Enumeration",
+ "type": "STRING"
+ }
+ ]
+ },
+ "actives": []
+}