Skip to content

Commit

Permalink
Merge branch 'main' into jonathan/codegen_map_json_schema
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathan-casey committed Nov 6, 2023
2 parents a458152 + e3111a0 commit 1cf7c33
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 15 deletions.
16 changes: 15 additions & 1 deletion lib/codegen/fromcto/java/javavisitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,15 @@ class JavaVisitor {
parameters.fileWriter.writeLine(0, `import ${namespace}.${typeName};` );
});

let hasImportedJavaMap = false;
classDeclaration.getOwnProperties().forEach(p => {
if(ModelUtil.isMap(p) && !hasImportedJavaMap) {
parameters.fileWriter.writeLine(0, 'import java.util.HashMap;');
parameters.fileWriter.writeLine(0, 'import java.util.Map;');
hasImportedJavaMap = true;
}
});

parameters.fileWriter.writeLine(0, 'import com.fasterxml.jackson.annotation.*;');
parameters.fileWriter.writeLine(0, '');

Expand Down Expand Up @@ -278,7 +287,12 @@ class JavaVisitor {
parameters.fileWriter.writeLine(1, '}');
break;
default:
parameters.fileWriter.writeLine(1, 'private ' + fieldType + ' ' + fieldName + ';' );
if (ModelUtil.isMap(field)) {
const decl = field.getModelFile().getType(field.ast.type.name);
parameters.fileWriter.writeLine(1, `private Map<${this.toJavaType(decl.getKey().getType())}, ${this.toJavaType(decl.getValue().getType())}> ${field.getName()} = new HashMap<>();`);
} else {
parameters.fileWriter.writeLine(1, 'private ' + fieldType + ' ' + fieldName + ';' );
}
}
} else {
parameters.fileWriter.writeLine(1, 'private ' + fieldType + ' ' + fieldName + ';' );
Expand Down
32 changes: 20 additions & 12 deletions test/codegen/__snapshots__/codegen.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1065,17 +1065,19 @@ import concerto.Asset;
import concerto.Transaction;
import concerto.Participant;
import concerto.Event;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.*;

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "$class")
public class Company extends Concept {
private String name;
private Address headquarters;
private CompanyProperties companyProperties;
private EmployeeDirectory employeeDirectory;
private EmployeeTShirtSizes employeeTShirtSizes;
private EmployeeProfiles employeeProfiles;
private EmployeeSocialSecurityNumbers employeeSocialSecurityNumbers;
private Map<String, String> companyProperties = new HashMap<>();
private Map<SSN, Employee> employeeDirectory = new HashMap<>();
private Map<SSN, TShirtSizeType> employeeTShirtSizes = new HashMap<>();
private Map<String, Concept> employeeProfiles = new HashMap<>();
private Map<String, SSN> employeeSocialSecurityNumbers = new HashMap<>();
public String getName() {
return this.name;
}
Expand Down Expand Up @@ -1253,6 +1255,8 @@ import concerto.Asset;
import concerto.Transaction;
import concerto.Participant;
import concerto.Event;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.*;

@JsonIgnoreProperties({"id"})
Expand All @@ -1272,7 +1276,7 @@ public abstract class Person extends Participant {
private String ssn;
private double height;
private java.util.Date dob;
private NextOfKin nextOfKin;
private Map<KinName, KinTelephone> nextOfKin = new HashMap<>();
public String getEmail() {
return this.email;
}
Expand Down Expand Up @@ -6871,17 +6875,19 @@ import concerto.Asset;
import concerto.Transaction;
import concerto.Participant;
import concerto.Event;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.*;

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "$class")
public class Company extends Concept {
private String name;
private Address headquarters;
private CompanyProperties companyProperties;
private EmployeeDirectory employeeDirectory;
private EmployeeTShirtSizes employeeTShirtSizes;
private EmployeeProfiles employeeProfiles;
private EmployeeSocialSecurityNumbers employeeSocialSecurityNumbers;
private Map<String, String> companyProperties = new HashMap<>();
private Map<SSN, Employee> employeeDirectory = new HashMap<>();
private Map<SSN, TShirtSizeType> employeeTShirtSizes = new HashMap<>();
private Map<String, Concept> employeeProfiles = new HashMap<>();
private Map<String, SSN> employeeSocialSecurityNumbers = new HashMap<>();
public String getName() {
return this.name;
}
Expand Down Expand Up @@ -7059,6 +7065,8 @@ import concerto.Asset;
import concerto.Transaction;
import concerto.Participant;
import concerto.Event;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.*;

@JsonIgnoreProperties({"id"})
Expand All @@ -7078,7 +7086,7 @@ public abstract class Person extends Participant {
private String ssn;
private double height;
private java.util.Date dob;
private NextOfKin nextOfKin;
private Map<KinName, KinTelephone> nextOfKin = new HashMap<>();
public String getEmail() {
return this.email;
}
Expand Down
14 changes: 13 additions & 1 deletion test/codegen/fromcto/java/javamissingplugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@ const sinon = require('sinon');

const JavaVisitor = require('../../../../lib/codegen/fromcto/java/javavisitor.js');
const AbstractPlugin = require('../../../../lib/codegen/abstractplugin.js');
const ModelUtil = require('@accordproject/concerto-core').ModelUtil;

const ClassDeclaration = require('@accordproject/concerto-core').ClassDeclaration;
const EnumDeclaration = require('@accordproject/concerto-core').EnumDeclaration;
const FileWriter = require('@accordproject/concerto-util').FileWriter;

let sandbox = sinon.createSandbox();

describe('JavaMissingPlugin', function () {
let javaVisit;
let mockFileWriter;
Expand Down Expand Up @@ -115,6 +118,15 @@ describe('JavaMissingPlugin', function () {

sinon.stub(javaVisit, 'startClassFile');
sinon.stub(javaVisit, 'endClassFile');

sandbox.stub(ModelUtil, 'isMap').callsFake(() => {
return true;
});
});

afterEach(() => {
sandbox.restore();

});

it('should fail to write a class declaration and call accept on each property', () => {
Expand All @@ -126,4 +138,4 @@ describe('JavaMissingPlugin', function () {
});
});

});
});
82 changes: 81 additions & 1 deletion test/codegen/fromcto/java/javavisitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ const sinon = require('sinon');
const JavaVisitor = require('../../../../lib/codegen/fromcto/java/javavisitor.js');

const ClassDeclaration = require('@accordproject/concerto-core').ClassDeclaration;
const MapDeclaration = require('@accordproject/concerto-core').MapDeclaration;
const ModelUtil = require('@accordproject/concerto-core').ModelUtil;
const EnumDeclaration = require('@accordproject/concerto-core').EnumDeclaration;
const EnumValueDeclaration = require('@accordproject/concerto-core').EnumValueDeclaration;
const Field = require('@accordproject/concerto-core').Field;
Expand All @@ -29,12 +31,21 @@ const ModelManager = require('@accordproject/concerto-core').ModelManager;
const RelationshipDeclaration = require('@accordproject/concerto-core').RelationshipDeclaration;
const FileWriter = require('@accordproject/concerto-util').FileWriter;

let sandbox = sinon.createSandbox();

describe('JavaVisitor', function () {
let javaVisit;
let mockFileWriter;
beforeEach(() => {
javaVisit = new JavaVisitor();
mockFileWriter = sinon.createStubInstance(FileWriter);
sandbox.stub(ModelUtil, 'isMap').callsFake(() => {
return false;
});
});

afterEach(() => {
sandbox.restore();
});

describe('visit', () => {
Expand Down Expand Up @@ -376,6 +387,36 @@ describe('JavaVisitor', function () {
acceptSpy.withArgs(javaVisit, Object.assign({},param,{mode:'setter'})).calledTwice.should.be.ok;
mockEndClassFile.withArgs(mockClassDeclaration, param).calledOnce.should.be.ok;
});

it('should write a class declaration, including imports for java.util Map & HashMap types', () => {
mockClassDeclaration.getIdentifierFieldName.returns('employeeID');
sandbox.restore();
sandbox.stub(ModelUtil, 'isMap').callsFake(() => {
return true;
});
javaVisit.visitClassDeclaration(mockClassDeclaration, param);

mockStartClassFile.withArgs(mockClassDeclaration, param).calledOnce.should.be.ok;
param.fileWriter.writeLine.callCount.should.deep.equal(9);
param.fileWriter.writeLine.getCall(0).args.should.deep.equal([0, 'import fruit.oranges;']);
param.fileWriter.writeLine.getCall(1).args.should.deep.equal([0, 'import fruit.apples;']);
param.fileWriter.writeLine.getCall(2).args.should.deep.equal([0, 'import java.util.HashMap;']);
param.fileWriter.writeLine.getCall(3).args.should.deep.equal([0, 'import java.util.Map;']);
param.fileWriter.writeLine.getCall(4).args.should.deep.equal([0, 'import com.fasterxml.jackson.annotation.*;']);
param.fileWriter.writeLine.getCall(5).args.should.deep.equal([0, '']);
param.fileWriter.writeLine.getCall(6).args.should.deep.equal([0, 'public class Bob {']);
param.fileWriter.writeLine.getCall(7).args.should.deep.equal([1, `
// the accessor for the identifying field
public String getID() {
return this.getEmployeeID();
}
`]);
param.fileWriter.writeLine.getCall(8).args.should.deep.equal([0, '}']);
acceptSpy.withArgs(javaVisit, Object.assign({},param,{mode:'field'})).calledTwice.should.be.ok;
acceptSpy.withArgs(javaVisit, Object.assign({},param,{mode:'getter'})).calledTwice.should.be.ok;
acceptSpy.withArgs(javaVisit, Object.assign({},param,{mode:'setter'})).calledTwice.should.be.ok;
mockEndClassFile.withArgs(mockClassDeclaration, param).calledOnce.should.be.ok;
});
});

describe('visitField', () => {
Expand Down Expand Up @@ -413,6 +454,45 @@ describe('JavaVisitor', function () {
param.fileWriter.writeLine.withArgs(1, 'private JavaType[] Bob;').calledOnce.should.be.ok;
});

it('should write a line with a HashMap', () => {
let param = {
fileWriter: mockFileWriter,
mode: 'field'
};

sandbox.restore();
sandbox.stub(ModelUtil, 'isMap').callsFake(() => {
return true;
});

const mockField = sinon.createStubInstance(Field);
const getType = sinon.stub();

mockField.ast = { type: { name: 'Dummy Value'} };
mockField.getModelFile.returns({ getType: getType });

const mockMapDeclaration = sinon.createStubInstance(MapDeclaration);
const getKeyType = sinon.stub();
const getValueType = sinon.stub();

mockField.getName.returns('Bob');
mockField.getType.returns('SpecialType');

getType.returns(mockMapDeclaration);
getKeyType.returns('String');
getValueType.returns('String');
mockField.getName.returns('Map1');
mockMapDeclaration.getName.returns('Map1');
mockMapDeclaration.isMapDeclaration.returns(true);
mockMapDeclaration.getKey.returns({ getType: getKeyType });
mockMapDeclaration.getValue.returns({ getType: getValueType });

javaVisit.visitField(mockField,param);

param.fileWriter.writeLine.withArgs(1, 'private Map<String, String> Map1 = new HashMap<>();').calledOnce.should.be.ok;
sandbox.reset();
});

it('should write a line defining a field', () => {
let mockField = sinon.createStubInstance(Field);
mockField.isField.returns(true);
Expand Down Expand Up @@ -673,4 +753,4 @@ describe('JavaVisitor', function () {
javaVisit.toJavaType('Penguin').should.deep.equal('Penguin');
});
});
});
});

0 comments on commit 1cf7c33

Please sign in to comment.