typescript – computed property on interface

You can’t have computed or calculated properties on interfaces since they omit implementation details, that’s the use of interfaces. For example, we can’t do this 🛑

export interface IUser {
  firstName?: string;
  lastName?: string;
  fullName?: string = this.firstName + this.lastName;
}

but we can just declare it in the interface and implement it in a class

export interface IUser {
  firstName?: string;
  lastName?: string;
  fullName?: string;
}
export class User implements IUser {
  constructor(public firstName?: string, public lastName?: string) {}

  get fullName(): string {
    return `${this.firstName} ${this.lastName}`;
  }
}

now let's see how we can instantiate those class

User user = new User('Jhon', 'Doe');
console.log(user.fullName); // Jhon Doe

the problem I had was the data was coming from a service

this.userService.query().pipe(
filter((res: HttpResponse) => res.ok),
map((res: HttpResponse) => res.body)
)
.subscribe((data: IUser[])=>{
this.users = data;
})

changing declared type of reponses won't make a difference 🤷

this.userService.query().pipe(
filter((res: HttpResponse) => res.ok),
map((res: HttpResponse) => res.body)
)
.subscribe((data: User[])=>{
this.users = data;
})

neither 'cast' (which in typescript its not casting but just an assertion) response objects to class type

this.userService.query().pipe(
filter((res: HttpResponse) => res.ok),
map((res: HttpResponse) => res.body)
)
.subscribe((data: IUser[])=>{
this.users = data.map(value => (value as User));
})

i tried to did it by copying properties to a new object of the correct class with spread operator syntax

this.userService.query().pipe(
filter((res: HttpResponse) => res.ok),
map((res: HttpResponse) => res.body)
)
.subscribe((data: IUser[])=>{
this.users = data.map(value => {
return {...new User(), ...value} as User;
});
})

it turns out spread syntax produce a plain or literal object so it can't be used to accomplish what we we're trying to do. We need to use the Object.assign method (be aware there could be undesirable or unexpected results).

this.userService.query().pipe(
filter((res: HttpResponse) => res.ok),
map((res: HttpResponse) => res.body)
)
.subscribe((data: IUser[])=>{
this.users = data.map(value => {
return Object.assign(new User(), value);
});
})

great! 😄

UPDATE: 2019-06-24
Although it worked I was assuming it would only be used in just one component, and of course it didn't.
So, it's way easier to just add the computed field in the domain object or DTO on the server, i.e.

UserDTO.java

public String getFullName() {
    return getFirstName() + " " + getLastName();
}

If you can't change the model or just insist on computing at client side, then it's better if you do it at a central location, i.e. the Service

  query(req?: any): Observable {
    return this.http.get('/api/users', { params: options, observe: 'response' })
      .pipe(
        map(res => {
          const users = res.body.map(user => {
            return Object.assign(new User(), user);
          });
          return new HttpResponse({...res, body: users});
        })
      );
  }

sources:
https://stackoverflow.com/questions/53238881/computed-property-in-typescript
https://stackoverflow.com/questions/49937677/how-to-merge-class-instances-in-typescript

angular – passing a complex (object or array) parameter to a popup dialog

In a jhipster generated app We created a component to confirm an action that is to be done on a batch of selected documents.

You can pass parameters as path params or query params, but most examples only tell you how to pass an id and then resolve it to an object. We already had an array of objects which we want to pass as parameters.
I suppose you could stringify them and pass them as one of the options above, but that would increase the length of the URL; with the advantage it can be shared and state would be restored. Nonetheless we decided to opt for the fourth option described in this answer to the stackoverflow question ‘Send data through routing paths in Angular’.

First we created our component to select the documents that are going to be processed, when the button is pressed we should confirm the action.
We used a PrimeNG table to allow the user to select the documents which we store in our ‘documentosSeleccionados’ variable.
The routerLink specifies it should navigate to a popup dialog, the trick here is we also specified a click action where we tell it to update the value on a Service property -as explained in the answer above-.

lote-firmar.component.html

        <button class="btn btn-primary float-right" (click)="documentoService.documentosSeleccionados = documentosSeleccionados"
                [routerLink]="['/', { outlets: { popup: 'lote/'+ lote.id + '/firmar/confirma'} }]"
                replaceUrl="true"
                queryParamsHandling="merge">
            <fa-icon [icon]="'file-signature'"></fa-icon>
            <span>
            Firmar
            </span>
        </button>
    <br/>
    <p-table #dt [value]="documentos" dataKey="id" selectionMode="multiple" [(selection)]="documentosSeleccionados">
        <ng-template pTemplate="header">
            <tr>
                <th style="width: 3em">
                    <p-tableHeaderCheckbox></p-tableHeaderCheckbox>
                </th>
                <th>Archivo</th>
                <th>
                    <p-dropdown [options]="estatusDocumentos" [style]="{'width':'100%'}" (onChange)="dt.filter($event.value, 'estatus', 'equals')"></p-dropdown>
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-documento>
            <tr>
                <td>
                    <p-tableCheckbox [value]="documento"></p-tableCheckbox>
                </td>
                <td>{{documento.archivo}}</td>
                <td>{{documento.estatus}}</td>
            </tr>
        </ng-template>
    </p-table>

lote-firmar.component.ts

@Component({
    selector: 'jhi-lote-firmar',
    templateUrl: './lote-firmar.component.html'
})
export class LoteFirmarComponent implements OnInit {
    lote: ILote;
    documentos: IDocumento[];
    documentosSeleccionados: IDocumento[];
    estatusDocumentos: SelectItem[];

    ... we inject the Service
    constructor(private activatedRoute: ActivatedRoute, private documentoService: DocumentoService) {}

The service is pretty straightforward, we just need to add the property where we’d like to pass to the popup dialog. We could even specified the type, but we didn’t in this case. Remember services are singletons, so we have just one instance of this class.

documento.service

@Injectable({ providedIn: 'root' })
export class DocumentoService {
    ... other properties
    public documentosSeleccionados;

    constructor(private http: HttpClient) {}

    ... we also have the method to send the objects to process to the server
    firmar(documentos: IDocumento[], keyPassword: string): Observable<EntityArrayResponseType> {
        const options = createRequestOption({ keyPassword });
        return this.http.post<IDocumento[]>(this.resourceUrl + '/firmar', documentos, {
            params: options,
            observe: 'response'
        });
    }
}

Finally, the popup dialog

lote-firmar-dialog.component.html

<form name="loteFirmarForm" autocomplete="off" (ngSubmit)="firmarDocumentos()">
    <div class="modal-header">
        <h4 class="modal-title">Se requiere contraseña</h4>
        ×
    </div>
    <div class="modal-body">

        <p id="jhi-delete-documento-heading">Para firmar los documentos seleccionados, ingresa la contraseña de tu archivo .key</p>
        <div class="col-md-8">
            <div class="form-group">

            </div>
        </div>
    </div>
    <div class="modal-footer">

             <span>Cancelar</span>


             <span>Firmar</span>

    </div>
</form>

since we inject the Documentos service already in this component, we can access the value passed as parameter trough the service and initialize our model in the NgOnInit method.

lote-firmar-dialog.component.ts

@Component({
    selector: 'jhi-lote-firmar-dialog',
    templateUrl: './lote-firmar-dialog.component.html'
})
export class LoteFirmarDialogComponent implements OnInit {
    ... other properties
    documentosSeleccionados: IDocumento[];

    ... this is where we inject the service
    constructor(private documentoService: DocumentoService, public activeModal: NgbActiveModal, private eventManager: JhiEventManager) {}

    ... this is where we read the array passed through the service
    ngOnInit() {
        this.documentosSeleccionados = this.documentoService.documentosSeleccionados;
    }

    ... then we can send this data to the server to be processed in this service
    firmarDocumentos() {
        this.documentoService.firmar(this.documentosSeleccionados, this.keyfilePassword).subscribe(
            response => {
                console.log('se enviaron los documentos a firmar, response:', response);
                this.eventManager.broadcast({
                    name: 'documentosListModification',
                    content: 'Los documentos se firmaron correctamente'
                });
                this.activeModal.dismiss(true);
            },
            error => {
                console.log('ocurrio un error al enviar los documentos a firmar', error);
                this.eventManager.broadcast({
                    name: 'documentosListModification',
                    content: 'Ocurrio un problema al firmar los documentos [' + error + ']'
                });
            }
        );
    }
}

done!

AngularJS – Invocar un servicio REST y adaptar la respuesta a nuestro modelo

Desarrollé un servicio web que regresa una respuesta al estilo de SmartGWT

{
"response": {
"status": 0,
"startRow": 0,
"endRow": 76,
"totalRows": 546,
"data": [
{"field1": "value", "field2": "value"},
{"field1": "value", "field2": "value"},
… 76 total records …
]
}
}

Queremos utilizar estos datos en nuestra plantilla

distritos.html

...
<label class="item item-input item-select">
                <div class="input-label">
                    Distrito
                </div>
                <select>
                    <option ng-repeat="distrito in distritos">
                        {{ distrito.descripcion }}
                    </option>
                </select>
            </label>
...

Hay dos formas para poder consumir esta respuesta en nuestra plantilla -a través de un servicio de AngularJS-

Una es utilizar una función transformResponse en la configuración del servicio de la siguiente manera

services.js

'use strict'
angular.module('Equinox.services', ['ngResource'])

    .factory('Distritos', ['$resource', function ($resource) {
        return $resource('http://localhost:8080/equinox/catalogos/distritos', {}, {
            'query': {method: 'GET', isArray: true, transformResponse: function(data){
                return angular.fromJson(data).response.data
            }}
        })
    }])

controllers.js

angular.module('Equinox.controllers', [])

    .controller('DistritosCtrl', ['$scope', 'Distritos', function ($scope, Distritos) {
        $scope.distritos = Distritos.query()

    }])

y la segunda forma es utilizar la respuesta tal y como viene del servidor

services.js

'use strict'
angular.module('Equinox.services', ['ngResource'])

    .factory('Distritos', ['$resource', function ($resource) {
        return $resource('http://localhost:8080/equinox/catalogos/distritos', {}, {
            'query': {method: 'GET', isArray: false}
        })
    }])

controllers.js

angular.module('Equinox.controllers', [])

    .controller('DistritosCtrl', ['$scope', 'Distritos', function ($scope, Distritos) {
        Distritos.query().$promise.then(function(data){
            $scope.distritos = data.response.data
        })
    }])

Fuentes:

Datanucleus (JDO) – Relaciones y propiedades de tipo objeto

En datanucleus existe un mecanismo llamado attach/detach que sirve para acceder a las propiedades de los objetos fuera del contexto de una transacción. Esto es muy útil, por ejemplo, cuando estructuras tu aplicación en librerías o capas.

Supongamos que tenemos la siguiente clase

    @PersistenceCapable
    public class Audiencia {</p><pre><code>    @PrimaryKey
    @Persistent
    Integer id;
    @Persistent
    Juez juez;
    @Persistent
    Date inicio;
    @Persistent
    Date fin;
    @Persistent
    TipoAudiencia tipo;

    public Audiencia(){
    }

    public static List&lt;Audiencia&gt; getAudiencias(Integer idJuez) {
        List&lt;Audiencia&gt; audiencias;
        PersistenceManager pm = PMF.get().getPersistenceManager();
        Transaction tx = pm.currentTransaction();
        try{
            tx.begin();
            String filter = "juez.id == :idJuez";
            Query query = pm.newQuery(Audiencia.class, filter);
            audiencias = (List&lt;Audiencia&gt;) pm.detachCopyAll((List&lt;Audiencia&gt;)query.executeWithArray(idJuez));
            tx.commit();
        }finally{
            if(tx.isActive()){
                tx.rollback();
            }
            pm.close();
        }
        return audiencias;
    }

}
</code></pre><p>

cabe destacar que dentro del contexto de la transacción podríamos leer las propiedades Juez y TipoAudiencia, datanucleus cargaría los objetos relacionados de forma «lazy loading». Pero si trataramos de leer alguna propiedad fuera de este contexto -es el caso cuando ejecutamos el método getAudiencias desde otra clase- está tendría el valor null. Datanucleus sólo hace el detach de las propiedades en el Default Fetch Group. Para poder utilizar las demás propiedades, podemos especificar un Fetch Group dinámico de la siguiente manera

    public static List getAudiencias(Integer idJuez, String[] fields) {
        List audiencias;
        PersistenceManager pm = PMF.get().getPersistenceManager();
        Transaction tx = pm.currentTransaction();
        try{
            tx.begin();
            FetchGroup fetchGroup = PMF.get().getFetchGroup(Audiencia.class, "fields");
            fetchGroup.addMembers(fields);
            pm.getFetchPlan().addGroup("fields");
            String filter = "juez.id == :idJuez";
            Query query = pm.newQuery(Audiencia.class, filter);
            audiencias = (List) pm.detachCopyAll((List)query.executeWithArray(idJuez));
            tx.commit();
        }finally{
            if(tx.isActive()){
                tx.rollback();
            }
            pm.close();
        }
        return audiencias;
    }

Fuentes:
http://www.datanucleus.org/products/accessplatform/jdo/fetchgroup.html
http://www.datanucleus.org/products/datanucleus/jdo/attachdetach.html
http://www.datanucleus.org/products/datanucleus/jdo/object
lifecycle.html

JDeveloper 11g – Changing default JVM

JDeveloper 11g – Changing default JVM

Cuando instalas JDeveloper 11g, este incluye el JDK (necesario para ejecutar la aplicación). El problema es que incluye una versión de 32bits. Si tu sistema operativo es a 64 bits -Ubuntu 12.04 por ejemplo- probablemente te aparezca un error como el siguiente

libX11.so.6: cannot open shared object file: No such file or directory

Para resolverlo hay que instalar un JDK a 64 bits y configurarlo en el archivo jdeveloper/jdev/jdev.conf

SetJavaHome /usr/lib/jvm/java-6-openjdk-amd64/

Ya que en mi caso utilizo OpenJDK.

via OTN Discussion Forums : Changing default JVM in Jdeveloper 11 ….

Java – Obtener el tipo de dato de las propiedades de un objeto

Para obtener el tipo de dato de las propiedades de un objeto podemos utilizar la reflexión.

Por ejemplo si tenemos las siguientes clases

public class Libro{
String isbn;
String titulo;
Autor autor;
}
public class Autor{
String id;
String nombre;
Date fechaNacimiento;
}

Un método para obtener el tipo de dato de una propiedad, incluso propiedades anidadas, sería el siguiente

private Class<?> getPropertyType(Class<?> clazz,String property){
 try{
 LinkedList<String> properties=new LinkedList<String>();
 properties.addAll(Arrays.asList(property.split("\\.")));
 Field field = null;
 while(!properties.isEmpty()){
 field = FieldUtils.getField(clazz,properties.removeFirst(),true);
 clazz=field.getType();
 }
 return field.getType();
 }catch(Exception e){
 throw new RuntimeException(e);
 }
}

Lo invocaríamos de la siguiente manera

Class<?> type=getPropertyType(Libro.class,"autor.fechaNacimiento");
System.out.println(type.toString()); //imprime java.util.Date

Notesé el uso de la clase FieldUtils de la librería Apache Commons Lang, cuyo método getField busca el campo recursivamente en la jerarquía de las clase y sus interfaces. Para agregar la librería a nuestro proyecto hay que agregar la siguiente dependencia


<dependency>
 <groupId>org.apache.commons</groupId>
 <artifactId>commons-lang3</artifactId>
 <version>3.1</version>
 </dependency>

Para listar todas las propiedades de un objeto recursivamente podemos utilizar como ejemplo el código de la clase FieldUtils.

Con la librería Jackson podemos obtener un esquema JSON de cualquier objeto. El detalle es que los tipos de datos que obtendríamos serían sólo los permitidos en JSON (string, number, boolean, object, array, null).

ObjectMapper mapper=new ObjectMapper();
System.out.println(mapper.generateJsonSchema(Libro.class));

Fuentes:
http://stackoverflow.com/questions/11125409/find-the-field-type-using-jackson-json
http://stackoverflow.com/questions/3567372/access-to-private-inherited-fields-via-reflection-in-java
http://wiki.fasterxml.com/JacksonJavaDocs
http://jackson.codehaus.org/1.8.8/javadoc/org/codehaus/jackson/map/ObjectMapper.html#generateJsonSchema(java.lang.Class)
http://wiki.fasterxml.com/JacksonTreeModel

Datanucleus – JDO valores nulos depués de la primer consulta

Recientemente empecé a utilizar Datanucleus para simplificar la persistencia y consulta de datos. Uno de los primeros problemas que tuve fue que al realizar una consulta por segunda vez, las propiedades del objeto eran nulas. Esto se debe al ciclo de vida de los objetos en Datanucleus, el cuál aparece en el log de la siguiente manera

13:07:41,197 DEBUG [DataNucleus.Lifecycle] – Object «mx.com.apestudio.videohaus.server.model.Video@6eb5ec12» (id=»mx.com.apestudio.videohaus.server.model.Video:bb56da010129448ab28f4486d32036b9    «) has a lifecycle change : «P_CLEAN»->»HOLLOW»

al cambiar del estado P_CLEAN a HOLLOW todas las propiedades, excepto la llave primaria, son reestablecidas a un valor nulo. Para evitar que esto suceda, podemos establecer la propiedad RetainValues a true en el archivo de configuración datanucleus.properties

datanucleus.RetainValues=true

al hacer esto, el log muestra lo siguiente

14:05:37,400 DEBUG [DataNucleus.Lifecycle] – Object «mx.com.apestudio.videohaus.server.model.Video@795cd696» (id=»mx.com.apestudio.videohaus.server.model.Video:bb56da010129448ab28f4486d32036b9    «) has a lifecycle change : «P_CLEAN»->»P_NONTRANS»

ahora el objeto pasó de un estado P_CLEAN a P_NONTRANS y conservó todas las propiedades con los valores obtenidos al realizar la primer consulta. Este modo es conveniente si sólo vas a realizar operaciones de lectura.

La otra opción es establecer la propiedad DetachAllOnCommit que, aunque es un poco mas costosa en cuanto a rendimiento, hace un ‘detach’ y ‘re-attach’ automático de los objetos. Esto es especialmente útil si vamos a actualizar alguna propiedad del objeto y queremos persistir los cambios.

datanucleus.DetachAllOnCommit=true

estas propiedades también podemos establecerlas mediante los métodos correspondientes del objeto PersistenceManager.

Cabe destacar que el problema de los valores nulos se presenta sólo cuando queremos leer propiedades del objeto fuera del contexto de una transacción.

Fuentes:
http://stackoverflow.com/questions/4630142/datanucleus-jdo-setting-fields-to-null
http://www.datanucleus.org/products/datanucleus/jdo/object_lifecycle.html
http://www.datanucleus.org/products/datanucleus/persistence_properties.html#RetainValues  
http://www.datanucleus.org/products/accessplatform_3_1/jdo/performance_tuning.html#Reading_persistent_objects_outside_a_transaction_and_PersistenceManager 

Jackson – JsonMappingException: No serializer found for class

Uitlizo Jackson para serializar objetos al formato JSON y enviarlos al cliente mediante servicios REST. A veces olvido, sobretodo al inicio de un proyecto, que por default Jackson intenta serializar mis objetos con un BeanSerializer. Esto significa que mi clase debe ser un JavaBean, es decir, tener un constructor sin argumentos y ‘getters’ y ‘setters’ para las propiedades que me interesa sean incluídas en la respuesta. Si tu clase no cumple estas condiciones, te arrojará la siguiente excepción:

org.codehaus.jackson.map.JsonMappingException: No serializer found for class mx.com.apestudio.videohaus.server.model.Video and no properties discovered to create BeanSerializer