Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
TEHIK
TEIS
auth-service
Commits
4711f385
Commit
4711f385
authored
Mar 19, 2020
by
Enriko Käsper
Browse files
Merge branch 'develop' into 'master'
Release See merge request teis/auth-service!14
parents
1401b3fb
b27545e7
Changes
9
Hide whitespace changes
Inline
Side-by-side
build.gradle
View file @
4711f385
...
...
@@ -59,6 +59,7 @@ allprojects {
compile
"ee.sm.ti.teis:common-api-gateway-lib:${commonApiGatewayVersion}"
compile
"ee.sm.ti.teis:service-common-lib:${commonsVersion}"
compile
"ee.sm.ti.teis:domain-request-lib:${commonsVersion}"
compile
"ee.sm.ti.teis:scheduler-service-lib:${schedulerVersion}"
annotationProcessor
(
"javax.annotation:javax.annotation-api:1.3.2"
,
)
...
...
gradle.properties
View file @
4711f385
theGroup
=
ee.sm.ti.teis
theVersion
=
0.2.0
commonsVersion
=
0.22.3-SNAPSHOT
commonApiGatewayVersion
=
0.23.0-SNAPSHOT
theVersion
=
0.3.0
commonsVersion
=
0.23.1
commonApiGatewayVersion
=
0.24.0
schedulerVersion
=
0.4.0
pluginVersion
=
0.0.19-SNAPSHOT
mapstructVersion
=
1.3.0.Final
service/src/main/java/ee/sm/ti/teis/authorization/AuthServiceApp.java
View file @
4711f385
...
...
@@ -6,13 +6,16 @@ package ee.sm.ti.teis.authorization;
import
ee.sm.ti.teis.aspects.RabbitListenerAspect
;
import
ee.sm.ti.teis.configuration.ExchangeConfig
;
import
ee.sm.ti.teis.configuration.QueueConfigurator
;
import
ee.sm.ti.teis.scheduler.job.executor.SystemJobExecutionListener
;
import
ee.sm.ti.teis.scheduler.job.executor.SystemJobsRegistry
;
import
ee.sm.ti.teis.servicecommon.config.PropertyLogger
;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.autoconfigure.SpringBootApplication
;
import
org.springframework.context.annotation.Import
;
@SpringBootApplication
@Import
({
PropertyLogger
.
class
,
ExchangeConfig
.
class
,
QueueConfigurator
.
class
,
RabbitListenerAspect
.
class
})
@Import
({
PropertyLogger
.
class
,
ExchangeConfig
.
class
,
QueueConfigurator
.
class
,
RabbitListenerAspect
.
class
,
SystemJobExecutionListener
.
class
,
SystemJobsRegistry
.
class
})
public
class
AuthServiceApp
{
public
static
void
main
(
String
[]
args
)
{
SpringApplication
.
run
(
AuthServiceApp
.
class
,
args
);
...
...
service/src/main/java/ee/sm/ti/teis/authorization/keycloak/KeycloakOfficialsService.java
View file @
4711f385
package
ee.sm.ti.teis.authorization.keycloak
;
import
ee.sm.ti.teis.exceptions.TeisResourceNotFoundException
;
import
lombok.extern.slf4j.Slf4j
;
import
org.keycloak.admin.client.Keycloak
;
import
org.keycloak.representations.idm.GroupRepresentation
;
import
org.keycloak.representations.idm.UserRepresentation
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.stereotype.Service
;
import
java.util.LinkedHashSet
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.stream.Collectors
;
@Service
@Slf4j
public
class
KeycloakOfficialsService
{
private
static
final
int
LIST_QUERY_BATCH_SIZE
=
100
;
private
final
Keycloak
keycloakTemplate
;
private
final
TiadKeycloakProperties
tiadKeycloakProperties
;
@Value
(
"${teis.group-prefix}"
)
private
String
teisGroupPrefix
;
public
KeycloakOfficialsService
(
Keycloak
keycloakTemplate
,
TiadKeycloakProperties
tiadKeycloakProperties
)
{
this
.
keycloakTemplate
=
keycloakTemplate
;
this
.
tiadKeycloakProperties
=
tiadKeycloakProperties
;
...
...
@@ -40,4 +52,46 @@ public class KeycloakOfficialsService {
.
groups
();
}
public
Set
<
UserRepresentation
>
getKeycloakTeisGroupUsers
()
{
Set
<
UserRepresentation
>
keycloakUsers
=
new
LinkedHashSet
<>();
Set
<
GroupRepresentation
>
keycloakTeisGroups
=
new
LinkedHashSet
<>();
Map
<
String
,
Long
>
countGroups
=
keycloakTemplate
.
realm
(
tiadKeycloakProperties
.
getRealm
())
.
groups
()
.
count
();
int
firstResult
=
0
;
while
(
firstResult
<
countGroups
.
get
(
"count"
))
{
List
<
GroupRepresentation
>
batchGroups
=
keycloakTemplate
.
realm
(
tiadKeycloakProperties
.
getRealm
())
.
groups
().
groups
(
firstResult
,
LIST_QUERY_BATCH_SIZE
);
for
(
GroupRepresentation
group
:
batchGroups
)
{
if
(
group
.
getName
().
startsWith
(
teisGroupPrefix
))
{
keycloakTeisGroups
.
add
(
group
);
List
<
GroupRepresentation
>
subGroups
=
group
.
getSubGroups
();
keycloakTeisGroups
.
addAll
(
subGroups
);
}
}
firstResult
+=
LIST_QUERY_BATCH_SIZE
;
}
for
(
GroupRepresentation
group
:
keycloakTeisGroups
)
{
log
.
info
(
"Start querying group members for {}."
,
group
.
getName
());
int
countMembers
=
keycloakTemplate
.
realm
(
tiadKeycloakProperties
.
getRealm
())
.
groups
().
group
(
group
.
getId
()).
members
().
size
();
log
.
info
(
"Get group members ({}) for {}."
,
countMembers
,
group
.
getName
());
firstResult
=
0
;
while
(
firstResult
<
countMembers
)
{
List
<
UserRepresentation
>
members
=
keycloakTemplate
.
realm
(
tiadKeycloakProperties
.
getRealm
())
.
groups
().
group
(
group
.
getId
()).
members
(
firstResult
,
LIST_QUERY_BATCH_SIZE
,
true
);
keycloakUsers
.
addAll
(
members
.
stream
()
.
filter
(
UserRepresentation:
:
isEnabled
)
.
collect
(
Collectors
.
toSet
()));
firstResult
+=
LIST_QUERY_BATCH_SIZE
;
}
}
return
keycloakUsers
;
}
}
service/src/main/java/ee/sm/ti/teis/authorization/officials/OfficialUsersService.java
0 → 100644
View file @
4711f385
package
ee.sm.ti.teis.authorization.officials
;
import
ee.sm.ti.teis.ErrorDTO
;
import
ee.sm.ti.teis.domain.officials.OfficialUser
;
import
ee.sm.ti.teis.domainrequest.DomainQueryResponseDto
;
import
ee.sm.ti.teis.domainrequest.DomainResponseDTO
;
import
ee.sm.ti.teis.domainrequest.DomainUpdateDTO
;
import
ee.sm.ti.teis.domainrequest.rabbit.TeisRabbitClient
;
import
ee.sm.ti.teis.errors.CommonErrorCode
;
import
ee.sm.ti.teis.exceptions.TeisBusinessException
;
import
ee.sm.ti.teis.servicerequest.RequestMetaDTO
;
import
org.springframework.amqp.rabbit.core.RabbitTemplate
;
import
org.springframework.core.ParameterizedTypeReference
;
import
org.springframework.stereotype.Service
;
import
java.util.List
;
import
static
ee
.
sm
.
ti
.
teis
.
types
.
enums
.
ObjectStatus
.
CURRENT
;
@Service
public
class
OfficialUsersService
extends
TeisRabbitClient
<
OfficialUser
>
{
public
OfficialUsersService
(
RabbitTemplate
msRabbitTemplate
)
{
super
(
msRabbitTemplate
);
}
List
<
OfficialUser
>
getCurrentOfficialUsers
(
RequestMetaDTO
requestMetaDTO
)
{
OfficialUser
item
=
new
OfficialUser
();
item
.
setObjectStatus
(
CURRENT
);
return
getItems
(
item
,
OfficialUsersQueryResponse
.
class
,
requestMetaDTO
);
}
OfficialUser
deleteOfficialUser
(
OfficialUser
officialUser
,
RequestMetaDTO
requestMetaDTO
)
{
return
deleteItem
(
officialUser
,
OfficialUserDomainResponse
.
class
,
requestMetaDTO
);
}
OfficialUser
createOfficialUser
(
OfficialUser
officialUser
,
RequestMetaDTO
requestMetaDTO
)
{
return
createItem
(
officialUser
,
OfficialUserDomainResponse
.
class
,
requestMetaDTO
);
}
public
OfficialUser
updateOfficialUser
(
OfficialUser
officialUser
,
RequestMetaDTO
requestMetaDTO
)
{
UpdateOfficialUserDomainRequest
requestDTO
=
new
UpdateOfficialUserDomainRequest
();
requestDTO
.
setPayload
(
officialUser
,
requestMetaDTO
);
ParameterizedTypeReference
<
OfficialUserDomainResponse
>
responseType
=
ParameterizedTypeReference
.
forType
(
OfficialUserDomainResponse
.
class
);
OfficialUserDomainResponse
resultDTO
=
msRabbitTemplate
.
convertSendAndReceiveAsType
(
requestDTO
.
routingKey
(),
requestDTO
,
responseType
);
if
(
resultDTO
!=
null
)
{
return
resultDTO
.
getPayload
();
}
throw
new
TeisBusinessException
(
CommonErrorCode
.
SYSTEM_ERROR
,
"No response from officials service."
);
}
public
static
class
OfficialUsersQueryResponse
extends
DomainQueryResponseDto
<
List
<
OfficialUser
>,
ErrorDTO
>
{
}
public
static
class
OfficialUserDomainResponse
extends
DomainResponseDTO
<
OfficialUser
,
ErrorDTO
>
{
}
public
static
class
UpdateOfficialUserDomainRequest
extends
DomainUpdateDTO
<
OfficialUser
,
ErrorDTO
>
{
}
}
service/src/main/java/ee/sm/ti/teis/authorization/officials/OfficialUsersSyncJob.java
0 → 100644
View file @
4711f385
package
ee.sm.ti.teis.authorization.officials
;
import
ee.sm.ti.teis.scheduler.domain.SystemJob
;
import
ee.sm.ti.teis.scheduler.job.executor.SystemJobExecutor
;
import
ee.sm.ti.teis.servicerequest.RequestMetaDTO
;
import
org.springframework.amqp.rabbit.core.RabbitTemplate
;
import
org.springframework.stereotype.Service
;
@Service
public
class
OfficialUsersSyncJob
extends
SystemJobExecutor
{
private
final
OfficialUsersSyncService
officialUsersSyncService
;
public
OfficialUsersSyncJob
(
RabbitTemplate
msRabbitTemplate
,
OfficialUsersSyncService
officialUsersSyncService
)
{
super
(
msRabbitTemplate
);
this
.
officialUsersSyncService
=
officialUsersSyncService
;
}
@Override
protected
String
getJobId
()
{
return
"auth.syncOfficialUsersFromKeycloak"
;
}
@Override
public
String
executeInternal
(
SystemJob
payload
,
RequestMetaDTO
requestMetaDto
)
{
return
officialUsersSyncService
.
syncOfficialUsers
(
requestMetaDto
);
}
}
service/src/main/java/ee/sm/ti/teis/authorization/officials/OfficialUsersSyncService.java
0 → 100644
View file @
4711f385
package
ee.sm.ti.teis.authorization.officials
;
import
ee.sm.ti.teis.authorization.keycloak.KeycloakOfficialsService
;
import
ee.sm.ti.teis.domain.officials.OfficialUser
;
import
ee.sm.ti.teis.servicerequest.RequestMetaDTO
;
import
lombok.extern.slf4j.Slf4j
;
import
org.keycloak.representations.idm.UserRepresentation
;
import
org.springframework.core.env.Environment
;
import
org.springframework.stereotype.Service
;
import
java.util.List
;
import
java.util.Optional
;
import
java.util.Set
;
import
static
ee
.
sm
.
ti
.
teis
.
servicecommon
.
util
.
ProfilesUtil
.
isTestProfile
;
import
static
java
.
text
.
MessageFormat
.
format
;
@Service
@Slf4j
public
class
OfficialUsersSyncService
{
private
final
OfficialUsersService
officialUsersService
;
private
final
KeycloakOfficialsService
keycloakService
;
private
boolean
isTestProfile
=
true
;
public
OfficialUsersSyncService
(
OfficialUsersService
officialUsersService
,
KeycloakOfficialsService
keycloakService
,
Environment
env
)
{
this
.
officialUsersService
=
officialUsersService
;
this
.
keycloakService
=
keycloakService
;
if
(
env
!=
null
)
{
this
.
isTestProfile
=
isTestProfile
(
env
);
}
}
String
syncOfficialUsers
(
RequestMetaDTO
requestMetaDTO
)
{
int
createdUsers
=
0
;
int
updatedUsers
=
0
;
int
deletedUsers
=
0
;
Set
<
UserRepresentation
>
keycloakUsers
=
keycloakService
.
getKeycloakTeisGroupUsers
();
List
<
OfficialUser
>
currentOfficialUsers
=
officialUsersService
.
getCurrentOfficialUsers
(
requestMetaDTO
);
log
.
info
(
"Found {} AD users from Keycloak and {} CURRENT TeIS official users."
,
keycloakUsers
.
size
(),
currentOfficialUsers
.
size
());
if
(
keycloakUsers
.
isEmpty
())
{
return
"No users found from Keycloak. Skip sync."
;
}
for
(
UserRepresentation
keycloakUser
:
keycloakUsers
)
{
Optional
<
OfficialUser
>
currentOfficialUserOptional
=
currentOfficialUsers
.
stream
()
.
filter
(
officialUser
->
officialUser
.
getIdCode
().
equals
(
keycloakUser
.
getUsername
())).
findFirst
();
if
(
currentOfficialUserOptional
.
isPresent
())
{
OfficialUser
currentOfficialUser
=
currentOfficialUserOptional
.
get
();
if
(!
keycloakUser
.
getFirstName
().
trim
().
equals
(
currentOfficialUser
.
getFirstName
().
trim
())
||
!
keycloakUser
.
getLastName
().
trim
().
equals
(
currentOfficialUser
.
getLastName
().
trim
()))
{
// update existing user name
currentOfficialUser
.
setFirstName
(
currentOfficialUser
.
getFirstName
().
trim
());
currentOfficialUser
.
setLastName
(
currentOfficialUser
.
getLastName
().
trim
());
officialUsersService
.
updateOfficialUser
(
currentOfficialUser
,
requestMetaDTO
);
updatedUsers
++;
}
}
else
{
// add new users
officialUsersService
.
createOfficialUser
(
mapOfficialUser
(
keycloakUser
),
requestMetaDTO
);
createdUsers
++;
}
}
// remove users
for
(
OfficialUser
officialUser
:
currentOfficialUsers
)
{
if
(
keycloakUsers
.
stream
().
noneMatch
(
keycloakUser
->
keycloakUser
.
getUsername
().
equals
(
officialUser
.
getIdCode
()))
&&
!
isTestUser
(
officialUser
))
{
officialUsersService
.
deleteOfficialUser
(
officialUser
,
requestMetaDTO
);
deletedUsers
++;
}
}
return
format
(
"Official service users were synchronized with Keycloak users. created={0}, updated={1}, deleted={2}"
,
createdUsers
,
updatedUsers
,
deletedUsers
);
}
private
OfficialUser
mapOfficialUser
(
UserRepresentation
keycloakUser
)
{
return
OfficialUser
.
builder
()
.
idCode
(
keycloakUser
.
getUsername
())
.
firstName
(
keycloakUser
.
getFirstName
())
.
lastName
(
keycloakUser
.
getLastName
())
.
build
();
}
boolean
isTestUser
(
OfficialUser
officialUser
)
{
// FIXME test should be test-, but this removes Test3 user from TEIS official users.
return
officialUser
.
getLastName
().
toLowerCase
().
startsWith
(
"test"
)
&&
isTestProfile
;
}
}
service/src/main/java/ee/sm/ti/teis/authorization/rabbit/JobExecutorQueueConfig.java
0 → 100644
View file @
4711f385
package
ee.sm.ti.teis.authorization.rabbit
;
import
ee.sm.ti.teis.configuration.QueueList
;
import
ee.sm.ti.teis.configuration.TeisQueue
;
import
ee.sm.ti.teis.scheduler.message.ExecuteSystemJobStartRequest
;
import
org.springframework.context.annotation.Configuration
;
import
java.util.ArrayList
;
import
static
ee
.
sm
.
ti
.
teis
.
scheduler
.
job
.
executor
.
JobExecutorQueueBaseConfig
.
EXECUTE_SYSTEM_JOB_QUEUE_NAME
;
@Configuration
public
class
JobExecutorQueueConfig
implements
QueueList
{
public
static
final
String
MS_EXECUTE_SYSTEM_JOB_QUEUE
=
"auth-service"
+
EXECUTE_SYSTEM_JOB_QUEUE_NAME
;
@Override
public
void
updateQueues
(
ArrayList
<
TeisQueue
>
queues
)
{
addMsQueue
(
queues
,
"msExecuteSystemJobsQueue"
,
new
ExecuteSystemJobStartRequest
().
routingKey
(),
MS_EXECUTE_SYSTEM_JOB_QUEUE
);
}
}
service/src/test/java/ee/sm/ti/teis/authorization/officials/OfficialUsersSyncServiceTest.java
0 → 100644
View file @
4711f385
package
ee.sm.ti.teis.authorization.officials
;
import
ee.sm.ti.teis.authorization.keycloak.KeycloakOfficialsService
;
import
ee.sm.ti.teis.domain.officials.OfficialUser
;
import
ee.sm.ti.teis.servicerequest.RequestMetaDTO
;
import
org.junit.jupiter.api.BeforeEach
;
import
org.junit.jupiter.api.Test
;
import
org.junit.jupiter.api.extension.ExtendWith
;
import
org.keycloak.representations.idm.UserRepresentation
;
import
org.mockito.InjectMocks
;
import
org.mockito.Mock
;
import
org.mockito.junit.jupiter.MockitoExtension
;
import
java.util.ArrayList
;
import
java.util.LinkedHashSet
;
import
java.util.List
;
import
java.util.Set
;
import
static
ee
.
sm
.
ti
.
teis
.
servicerequest
.
UserType
.
OFFICIAL_USER
;
import
static
ee
.
sm
.
ti
.
teis
.
utils
.
TestUtils
.
createRequestMeta
;
import
static
java
.
util
.
Collections
.
emptyList
;
import
static
java
.
util
.
Collections
.
emptySet
;
import
static
java
.
util
.
UUID
.
randomUUID
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
import
static
org
.
mockito
.
ArgumentMatchers
.
any
;
import
static
org
.
mockito
.
Mockito
.*;
@ExtendWith
(
MockitoExtension
.
class
)
public
class
OfficialUsersSyncServiceTest
{
@Mock
private
OfficialUsersService
officialUsersService
;
@Mock
private
KeycloakOfficialsService
keycloakService
;
@InjectMocks
private
OfficialUsersSyncService
officialUsersSyncService
;
private
RequestMetaDTO
requestMetaDTO
;
@BeforeEach
void
setUp
()
{
requestMetaDTO
=
createRequestMeta
(
randomUUID
().
toString
(),
OFFICIAL_USER
,
randomUUID
().
toString
(),
emptyList
());
}
@Test
void
syncShouldNotStart_when_noUsersFromKeycloak
()
{
when
(
keycloakService
.
getKeycloakTeisGroupUsers
()).
thenReturn
(
emptySet
());
when
(
officialUsersService
.
getCurrentOfficialUsers
(
any
())).
thenReturn
(
emptyList
());
String
result
=
officialUsersSyncService
.
syncOfficialUsers
(
requestMetaDTO
);
assertThat
(
result
).
contains
(
"No users found "
);
}
@Test
void
sync_should_create_new_users
()
{
when
(
keycloakService
.
getKeycloakTeisGroupUsers
()).
thenReturn
(
getNewKeycloakUsers
());
when
(
officialUsersService
.
getCurrentOfficialUsers
(
any
())).
thenReturn
(
emptyList
());
String
result
=
officialUsersSyncService
.
syncOfficialUsers
(
requestMetaDTO
);
assertThat
(
result
).
contains
(
"created=3"
);
verify
(
officialUsersService
,
times
(
3
)).
createOfficialUser
(
any
(),
any
());
verify
(
officialUsersService
,
times
(
0
)).
updateOfficialUser
(
any
(),
any
());
verify
(
officialUsersService
,
times
(
0
)).
deleteOfficialUser
(
any
(),
any
());
}
@Test
void
sync_should_update_existing_users_if_name_changed
()
{
when
(
keycloakService
.
getKeycloakTeisGroupUsers
()).
thenReturn
(
getNewKeycloakUsers
());
when
(
officialUsersService
.
getCurrentOfficialUsers
(
any
())).
thenReturn
(
getOfficialUsers
());
String
result
=
officialUsersSyncService
.
syncOfficialUsers
(
requestMetaDTO
);
assertThat
(
result
).
contains
(
"created=1"
);
assertThat
(
result
).
contains
(
"updated=1"
);
assertThat
(
result
).
contains
(
"deleted=0"
);
verify
(
officialUsersService
,
times
(
1
)).
createOfficialUser
(
any
(),
any
());
verify
(
officialUsersService
,
times
(
1
)).
updateOfficialUser
(
any
(),
any
());
verify
(
officialUsersService
,
times
(
0
)).
deleteOfficialUser
(
any
(),
any
());
}
@Test
void
sync_should_delete_users_removed_from_keycloak
()
{
when
(
keycloakService
.
getKeycloakTeisGroupUsers
()).
thenReturn
(
getNewKeycloakUsers
());
when
(
officialUsersService
.
getCurrentOfficialUsers
(
any
())).
thenReturn
(
getOfficialUsersToDelete
());
String
result
=
officialUsersSyncService
.
syncOfficialUsers
(
requestMetaDTO
);
assertThat
(
result
).
contains
(
"created=2"
);
assertThat
(
result
).
contains
(
"updated=0"
);
assertThat
(
result
).
contains
(
"deleted=1"
);
verify
(
officialUsersService
,
times
(
2
)).
createOfficialUser
(
any
(),
any
());
verify
(
officialUsersService
,
times
(
0
)).
updateOfficialUser
(
any
(),
any
());
verify
(
officialUsersService
,
times
(
1
)).
deleteOfficialUser
(
any
(),
any
());
}
Set
<
UserRepresentation
>
getNewKeycloakUsers
()
{
Set
<
UserRepresentation
>
newUsers
=
new
LinkedHashSet
();
UserRepresentation
user1
=
new
UserRepresentation
();
user1
.
setFirstName
(
"firstName1"
);
user1
.
setLastName
(
"lastName1"
);
user1
.
setUsername
(
"11111"
);
newUsers
.
add
(
user1
);
UserRepresentation
user2
=
new
UserRepresentation
();
user2
.
setFirstName
(
"firstName2"
);
user2
.
setLastName
(
"lastName2"
);
user2
.
setUsername
(
"22222"
);
newUsers
.
add
(
user2
);
UserRepresentation
user3
=
new
UserRepresentation
();
user3
.
setFirstName
(
"firstName3"
);
user3
.
setLastName
(
"lastName3"
);
user3
.
setUsername
(
"33333"
);
newUsers
.
add
(
user3
);
return
newUsers
;
}
List
<
OfficialUser
>
getOfficialUsers
()
{
List
<
OfficialUser
>
newUsers
=
new
ArrayList
<>();
OfficialUser
user1
=
OfficialUser
.
builder
().
firstName
(
"firstName1"
).
lastName
(
"lastName1"
).
idCode
(
"11111"
).
build
();
newUsers
.
add
(
user1
);
OfficialUser
user2
=
OfficialUser
.
builder
().
firstName
(
"firstName2-NEW"
).
lastName
(
"lastName2-NEW"
).
idCode
(
"22222"
).
build
();
newUsers
.
add
(
user2
);
return
newUsers
;
}
List
<
OfficialUser
>
getOfficialUsersToDelete
()
{
List
<
OfficialUser
>
newUsers
=
new
ArrayList
<>();
OfficialUser
user1
=
OfficialUser
.
builder
().
firstName
(
"firstName1"
).
lastName
(
"lastName1"
).
idCode
(
"11111"
).
build
();
newUsers
.
add
(
user1
);
OfficialUser
user2
=
OfficialUser
.
builder
().
firstName
(
"firstName5"
).
lastName
(
"lastName5"
).
idCode
(
"55555"
).
build
();
newUsers
.
add
(
user2
);
return
newUsers
;
}
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment