Java

Optimistic Lock

Fórumok

Lehet, hogy nem jól értek valamit.

Van 2 alkalmazás szerver. Nincs az Entity cache szinkronban.

Amikor kiíratom az SQL-t amit optimistic lock esetén végrehajt, egy ilyesmit látok: update version=?version+1 where version=?version and id=?id; Ez alapján úgy gondolnám, hogy nem lehet 2 írás ugyanazon a rekordon. Vagy mégis? Úgy tűnik mintha ennek ellenére 2x íródna nagyon ritkán ugyanaz a rekord, nem dob Exception-t.

Vaadin (Java UI framework) tapasztalatok?

Fórumok

Még az ünnepek előtt jött valahol szembe a Vaadin (https://vaadin.com), ami első (és egyelőre sokadik) ránézésre is olyan frameworknek látszik, aminek használatát érdemes lenne fontolóra venni.

Amúgy sem szeretem a frontendet; JavaScripttől, CSS-től stb., kiráz a hideg.

De azt vettem észre, hogy kis fejlesztőcsapat lévén (van 1 db UX-es, de ő is inkább designer, mint fejlesztő, a többi lényegileg mind backend) számos belső tool-ra egyszerűen nem jut idő és energia frontendet fejleszteni, mert a Postman-nel való tutujgatás "elégségesen jó" megoldás.

Szóval első körben leginkább belső tool-ok UI fejlesztésére használnám, nem pedig a publikus oldalunkat akarnám újraírni benne.

A kérdés: használta-e valaki a Vaadin-t éles környezetben (nem példakódok otthon bizergetése), és ha igen, akkor mik voltak a tapasztalatok vele?

Mennyire egyszerű vele egy frontendet összehozni?

Mennyire bugos?

Hogyan lehet debugolni?

Milyen előnyöket/hátrányokat tapasztaltatok?

Stb. stb.

Köszi!

50 felett piacképes-e még egy Java programozó?

Fórumok

Még fiatalos a kinézetem. Visszajelzések szerint 5-10 évet simán letagadhatok. A modernebb technológiák vonzanak és még van bennem tudásvágy is.

A mostanában szokásos videó interjúkon (itt kevésbé látszik, hogy oldalt már őszülök) / feladatokon is átmegyek simán.

Az önéletrajzomból nem derül ki a korom, sőt ott is a 10 évvel fiatalabb jön ki egy véletlen folytán.

Ma raktam magamban össze a képet, hogy ahol modernebb technológiákat használnak, ott valószínűleg fiatalabbakat is várnak.

Azaz addig nincs semmi baj, amíg nem kérik be az adataimat. Jó ajánlatokat is kapok. 1.5 fölötti mind. Viszont amikor sejtésem szerint a beküldött adatok alapján meglátják, hogy nemrég elmúltam 50, jönnek a visszahúzódások.

Soha sem vágytam vezetői pozícióba. Mentorálni viszont mindig szerettem.

Lehet vissza kell lépnem a régebbi technológiákhoz? Azoknál nem volt gond ennyire, olyan helyekre simán felvettek volna. Igaz ott mindegyiken öreg szakikat is láttam. Több helyen GWT-t tolnak még. Volt ahol JDBC megy még. Stb. Az egyikre rákérdezve azt mondták felvettek ugyan embereket, de ha meggondolom magam szívesen látnak.
A régi munkahelyemre is visszavennének, ott JEE van. A Spring ott viszont tiltott. Pedig simán lehetne sok esetben használni.

Xml-ben nagy fájlok base64-gyel kódolva

Fórumok

Már 1 napot eltöltöttem ezzel a feladattal és nem igazán látok megoldást.

SOAP: Jaxb 2.3.3 + Spring.

Kb. 400 megás fájlokat kellene XML-ben visszaadnom base64 kódolással.

Valahogy így néz ki az XSD ezen része: 

type="xs:base64Binary" xmime:expectedContentTypes="application/octet-stream"

 

A Java-ban így van beállítva:

.setDoc(new DataHandler(new FileDataSource(f)));

 

Jelenleg olyan 4G-át eszik 1db 400 megás fájlnál.

Jó lenne ha streamelné inkább mint betölti memóriába a teljes fájlt stb.
com.sun.xml.bind.v2.runtime.unmarshaller.Base64Data.class:

try {
    ByteArrayOutputStreamEx baos = new ByteArrayOutputStreamEx(1024);
    InputStream is = this.dataHandler.getDataSource().getInputStream();
    baos.readFrom(is);
    is.close();
    this.data = baos.getBuffer();
    this.dataLen = baos.size();
} catch (IOException var3) {
    this.dataLen = 0;
}

Mert a főnökség viszont szeretné, ha mindez elmenne <1G rammal. Ha lehet 512 megával.

Ahogy debugoltam úgy látom alapból betölti a teljes fájlt. Majd azon még dolgozik a base64 kódolás miatt és úgy rakja be az XML-be. Gondolom a Content-Lenght-et is így állítja be (de ez nem lenne fontos).

Van ötletetek valami megoldásra?

[ Megoldva ] Javascript USB-kezelési probléma

Fórumok

Egy böngésző alapú alkalmazásból javascripttel kommunikálok USB-n keresztül az xterm.js segítségével.

Mivel a soros kommunikációt csak felhasználói beavatkozásra engedi megnyitni a Chrome (Firefox még úgy sem), így jelenleg, ha a felhasználó megnyom egy gombot, akkor meg tudom nyitni az USB kapcsolatot, adatot tudok cserélni az eszközzel, és utána le tudom zárni a kapcsolatot. Minden megnyitáshoz a felhasználónak ki kell választania a soros portot. Ez működik, de nehézkes.

Szerettem volna egy megnyitás és egy lezárás gombot is készíteni, de itt kezdődött a probléma. Ha egy külön esemény nyitja meg a soros portot, akkor hiába küldök rá bármit, már nem működik.

Azaz a következő kód megy:

function on_click() {
   var sc = new SerialComm();
   sc.sendCmd( command );
   sc.close();
}

A következő pedig nem:

var sc;

function on_click_open() {
   sc = new SerialComm();
}

function on_click_send() {
   sc.sendCmd( command );
   sc.close();
}

Hibaüzenetet nem kapok, csak nem megy.

Van valakinek ötlete, mi lehet a probléma? Vagy ez valamilyen biztonsági megkötés, és így soha nem is fog menni, csak egy eseményben?

Megoldás: gond nélkül megy külön a megnyitás és a kommunikáció, nincs korlátozás. Én hibáztam a SerialComm osztályon belül. :(

Vaadin újrafelhasználható felületi elemek

Fórumok

Most ismerkedek a Vaadinnal.Azt a feladatot kaptam, hogy alakítsak ki olyan kódbázist, amiben újra felhasználható elemek vannak.
Itt viszont állandó küzdés volt eddig.

A lényeg a kód, így mutatok példát:

public class AComponent extends VerticalLayout implements MyComponent {

    private static final String PERSON = "Személy";
    private static final String ORGANIZATION = "Szervezet";

    private ADto aDto = new ADto();

    private ComboBox<String> type = new ComboBox<>();

    private PersonComponent personComponent;

    private OrganizationComponent organizationComponent;

    private Binder<ADto> binder = new BeanValidationBinder<>(ADto.class);

    public AComponent(String title) {
        binder.forField(type).bind(ADto::getType, ADto::setType);
        //binder.bindInstanceFields(true);
        binder.setBean(aDto);

        add(new H3(title));
        setPadding(false);

        type.setPlaceholder("<válasszon>");
        type.setItems(PERSON, ORGANIZATION);
        add(type);

        VerticalLayout sumbitterDataContainer = new VerticalLayout();
        sumbitterDataContainer.setPadding(true);
        sumbitterDataContainer.setSpacing(false);
        add(sumbitterDataContainer);

        type.addValueChangeListener(listener -> {
            if (isPerson()) {
                personComponent = new PersonComponent(sumbitterDataContainer);
            } else {
                organizationComponent = new OrganizationComponent(sumbitterDataContainer);
            }
        });
    }

    @Override
    public boolean validate() {
        boolean valid = binder.validate().isOk();
        if (valid && isPerson()) {
            valid = personComponent.validate();
        }
        if (valid && isOrganization()) {
            valid = organizationComponent.validate();
        }

        return valid;
    }
    private boolean isOrganization() {
        return ORGANIZATION.equals(type.getValue());
    }

    private boolean isPerson() {
        return PERSON.equals(type.getValue());
    }
}

public class PersonComponent extends VerticalLayout implements MyComponent {

    private PersonDto personDto = new PersonDto();
    private NameComponent personName = new NameComponent("Viselt név");
    private NameComponent birthName = new NameComponent("Születési név");

    private Binder<PersonDto> binder = new BeanValidationBinder<>(PersonDto.class);

    public PersonComponent(FlexComponent container) {
        binder.bindInstanceFields(this);
        binder.setBean(personDto);

        addDataFields(container);
    }

    @Override
    public boolean validate() {
        return binder.isValid() && personName.validate() && birthName.validate();
    }

    private void addDataFields(final FlexComponent container) {
        container.removeAll();
        container.add(personName, birthName);
    }
}

public class PersonDto {
    private NameDto personName;
    private NameDto birthName;
    private NameDto mothersName;
    private BirthplaceDto birthplace;
    private LocalDate birthdate;
    // getters, setters...
}

public class ADto {

    @NotNull
    @NotEmpty
    @NotBlank
    @Size(min = 1)
    private String type;

    private PersonDto personDto;

    private OrganizationDto organizationDto;
    // getters, setters...
}

Azaz pl. van egy névbekérő rész ami ismétlődhet több formon is. 

Körülnéztem a Vaadin oldalán is, de csak egyszerű példák vannak. Ahol mindent feldobálsz egy form-ra, és nem használsz újra részeket. Kerestem Google-el is, de nem találtam komolyabb példákat.

1.) Az elképzelésem az volt, hogy A dto-kon levő annotációkkal tudom kontrollálni a felületen megjelenő hibaüzeneteket.
Tehát ha pl. kötelező megadni a AComponent type lenyílóját, ha pl. rákattint egy gombra amivel mentené a formot és validálja is közben a validate metódussal, akkor majd szépen kiírja a hibaüzenetet, hogy "nem lehet üres" a type mező alá. De ez nem történik meg. :( Látható, hogy ráraktam szinte minden létező annotációt. De a binder.isValid() azt mondja valid, amikor null az értéke.

2.) Valamint eredetileg arra gondoltam, hogy biztos van valami automatizáció, amely egy ilyen Component tree-n végig tud menni és a bevitt adatokból létrehoz egy ADto-t, benne a PersonDto-val, benne a NameDto-kkal stb. Úgy tűnik ilyen nincs. :(

Az is lehet csak rossz helyen kutatok és van valami egyszerű megoldás is, ami működik is.
Van valakinek valami megoldása erre?

Integer keresése integerekben

Fórumok

A feladat:

Megyek végig egy integer listán. Ami megfelelő integer, azt berakom egy másik listába. Az eredeti lista sorrend nem változhat meg az eredmény listában.

Ha az integer már szerepel az eredmény listában, akkor nem adhatom hozzá (azaz nem lehetnek duplikáltak az eredményekben).

Max. olyan 400-500 ezer integer lehet az eredménylistában.

Az eredménylistának nem kell tartalmaznia mind a 400-500 ezer sort. Mivel lapozható, így csak az aktuális oldalszámnak megfelelően pl. 100 db-nak.

Jelenleg HashSet-el oldottam meg.

Viszont nem ártana a memóriára is figyelni. CPU-ra is figyelni kell, de arra most ideiglenesen jó a + HashSet töltése.

Tudom van a Bloom filter is, de az nem 100%-os. Viszont valami hasonló megoldást keresnék.

Java - `-XX:CompressedClassSpaceSize` állítás mennyire baj

Fórumok

Sziasztok,

Van néhány, JVM11 felett futó appunk k8s-en. Néhány hete történt, hogy a k8s egyszerre lőtte ki egy deployment összes podját, OOMKilled okkal a tesztkörnyezetben. Szerintem ennek nem kellett volna megtörténnie - a Javas appok a saját igényeiknek beállított `-Xmx`-szel futnak (3200m), a pod memória requestje 4Gi, limitje 5. 

Utólagos vizsgálatok alapján az alábbiakat sikerült megszülnöm:

  • A memóriahasználat a pod indulásától kúszik fel, normál esetben megáll valahol 4.5 Gb környékén
  • A bekötött micrometer szerint a heap max tökéletesen bennemarad a 3200m-ben, de a nonheap memória max ~1.2 Gb.
  • lásd a képet lejjebb, de amivel el vagyok veszve, hogy a JVM kapásból befoglalja a micrometer által a `jvm_memory_max_bytes`-ban mondott értéket?
    • ha igen, akkor részben boldog vagyok, mert a JVM Heap max + JVM Non-Heap max kiadja azt, amit a k8s szerint a pod memóriában lefoglal a nap végére
      • cserébe mintha a heapnél nem így működne, lásd a nap elejét. Tehát memória usage = JVM Heap Committed + JVM NonHeap max?
      • miért?
    • ha nem, akkor miért mond a k8s akkora memória használatot, ami a `sum(jvm_memory_max_bytes)`-nak felel meg?

Namost, ha helyesen értem az interneten talált doksikat, és a micrometer metrikáit, akkor a nonheap áll:

  • CodeHeap 'non-nmethods' (a jvm_memory_max_bytes 5 megabájtot mond rá)
  • CodeHeap 'non-profiled nmethods' (a jvm_memory_max_bytes ~117 megabájtot mond rá)
  • CodeHeap 'profiled nmethods' (a jvm_memory_max_bytes ~117 megabájtot mond rá)
  • Compressed Class Space (a jvm_memory_max_bytes 1 gigabájtot mond rá)
  • Metaspace (a jvm_memory_max_bytes -1-et mond rá)

Odáig eljutottam a doksi alapján, hogy a Compressed Class Space méretét a `-XX:CompressedClassSpaceSize` kapcsolóval tudom állítani, és hogy a default értéke 1 gigabájt. A kérdésem az, hogy ezt az 1 gigabájtot a JVM lefoglalja egyből induláskor, akár rak oda adatot, akár nem? A jvm_memory_used_bytes metrika szerint ebből a Compressed Class Space-ből az utóbbi ~30 napaban sosem volt több, mint ~30 mega használva, és az is szélsőérték.

TLDR két kérdésem van, hátha valaki nagyon otthon van JVM memory tuningban:

  • Ha hagyom a `-XX:CompressedClassSpaceSize`-ot defaulton (~nem adom meg), akkor ezt az 1 gigabájtot a JVM lefoglalja egyből induláskor, akár rak oda adatot, akár nem?
  • Ha lejjebb veszem az `-XX:CompressedClassSpaceSize`-ot (de még mindig a valós használat többszörösére, mondjuk 256 megára, szép kerek szám), akkor milyen veszélyeket rántok magamra?

Megpróbáltam végigtúrni az internetet, de nem nagyon találtam semmi hasznosat elsőre. Ha van jó doksid, vagy releváns tapasztalatod, megköszönöm.

Köszi előre is,

float cseréje double-ra a teljes projectben (IntelliJ IDEA)

Fórumok

Szeretnénk lecserélni a float típust double-re a teljes projectben.

Mindezt úgy hogy a primitív típust primitív típusra (float -> double) az osztályt pedig osztályra (Float -> Double).

Nyújt ehhez valami refactoring támogatást az IntelliJ IDEA vagy bármi más? Jó lenne valami előzetes megtekintési lehetőség amit az IDEA egyébként is fel szokott ajánlani refactor-nál, mert nem biztos, hogy mégis mindenhol le kell cserélni, szóval jó lenne ezt ellenőrzötten végezni, de ha ilyen lehetőség nincs akkor az is jó ha tényleg mindenhol lecseréli első körben aztán majd "manuálisan" ellenőrzünk minden előfordulást.